码迷,mamicode.com
首页 > 其他好文 > 详细

重修课程day35(网络编程九之协程)

时间:2017-10-18 00:28:25      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:serve   迭代   word   join()   .com   day   pytho   eset   ret   

什么是用户态和内核态:

 内核态:当一个任务(进程)执行系统调用而陷入了内核代码中执行,这就叫做内核态。

 用户态:当用户在执行自己的代码时,这就叫在用户态

  内核态和用户态的详情:http://www.cnblogs.com/viviwind/archive/2012/09/22/2698450.html

psw程序状态寄存器:程序状态字(Program Status Word, PSW)又称状态寄存器,主要用于反映处理器的状态及某些计算结果以及控制指令的执行。

  psw程序状态寄存器详情:http://blog.csdn.net/liuqinglong_along/article/details/51645477

操作系统应用级的识别:每一个cpu都有自己的指令集。操作系统控制着所有的硬件,也就是说操作系统知道CPU所有的指令集。而应用程序只能靠着操作系统来控制着硬件。也就是说CPU的一些指令集是与应用程序有关的。

一 协程()Coroutine

 1 什么叫协程:单线程内实现并发,又称为微线程或者钎程。说白了就是协程是一种用户态的轻量级线程,协程就是用户程序自己控制调度的。

 怎么在单线程下实现并发:用户从应用程序级别单线程下的切换,注意的是遇到了IO才切。(切换时保存好当时执行的状态)

 协程就是线程内部调度的;而线程和进程都是由操作系统来调度的。

 2 协程的优缺点

  协程的优点:①协程的切换开销更小,属于程序级别的切换,因此操作系统根本就感知不到,因而更加轻量级。

        ②单线程内实现了并发,从而最大限度的利用的CPU。

  协程的缺点:①协程的本质就是在单线程内,因此无法使用多核。(只能创建多个进程,进程内在创建多个线程,线程内在创建协程)

        ②协程只在单线程下,因此只要是所有协程阻塞,这个线程就会被阻塞。

二 协程的创建

 创建方式一:生成器函数创建

  为什么迭代器还要有iter方法:主要用于for循环,因为for循环里面自带iter和next方法,所以在一个迭代器使用for循环的时候还是需要iter 一下的。

def producer():
    g=consumer()
    next(g)
    for i in range(100):
        print(‘alex_‘,i)
        g.send(i)

def consumer():
    while True:
        n = yield
        print(‘egon_‘,n)

producer()

 创建方式二:greenlet模块创建

  switch:提交任务

from greenlet import greenlet
def ect(name):
    print(‘%s ect 1‘%name)
    g2.switch(‘egon‘)
    print(‘%s ect 2‘%name)
    g2.switch(‘egon‘)

def paly(name):
    print(‘%s paly 1‘%name)
    g1.switch(‘alex‘)
    print(‘%s paly 2‘%name)

g1=greenlet(ect)
g2=greenlet(paly)
g1.switch(‘alex‘)

 注意方式一和方式二切换只是实现了单纯的切换。只能一个代码执行完毕后才切换,无法检测到IO。反而还浪费了时间,不建议使用。

 创建方式三:gevent模块的创建

 gevent模块的作用:①检测IO;②自动的切换,切换时还能保存当时执行的状态。

 gevent模块的常用方法

  gevent.skeep:睡眠几秒,用这个可以创建IO。

  spawn:提交任务。括号里面加上一个函数,如果有参数可以传入参数。   

  joinall:等待执行。(等待所有的任务提交完毕过后才执行)

gevent方式1:

import gevent
import time
def ect(name):
    print(‘%s ect 1‘%name)
    gevent.sleep(2)
    print(‘%s ect 2‘%name)

def paly(name):
    print(‘%s paly 1‘ % name)
    gevent.sleep(1)
    print(‘%s paly 2‘ % name)

start=time.time()
s1=gevent.spawn(ect,‘alex‘)
s2=gevent.spawn(paly,‘egon‘)

gevent.joinall([s1,s2])
print(time.time()-start)

  joinall相当于是多个join的一样,也就是多个join的简化版。括号里面需要传入对象,而对象的格式就是一个字典的格式。  

from  gevent import monkey;monkey。patch_all():加上补丁。

from gevent import monkey;monkey.patch_all()
import gevent
import time
def ect(name):
    print(‘%s ect 1‘%name)
    time.sleep(2)
    print(‘%s ect 2‘ % name)

def paly(name):
    print(‘%s paly 1‘%name)
    time.sleep(1)
    print(‘%s paly 2‘ % name)

start=time.time()
s1=gevent.spawn(ect,‘alex‘)
s2=gevent.spawn(paly,‘egon‘)
gevent.joinall([s1,s2])
print(time.time()-start)

  补丁的作用:因为gevent不能自动的识别除了gevent以外的IO,因此加上一个补丁,这样就可以识别替他的情况产生的IO了。

基于协程实现单线程下的并发效果:

服务端:

from gevent import monkey;monkey.patch_all()
import gevent
from multiprocessing import Process
from socket import *

def server(ip,port):
    s = socket(AF_INET, SOCK_STREAM)
    s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    s.bind((ip,port))
    s.listen(5)
    while True:
        conn,addr=s.accept()
        print(‘%s:%s‘ % (addr[0], addr[1]))
        g1=gevent.spawn(talk,conn,addr)

def talk(conn,addr):
    while True:
        try:
            data=conn.recv(1024)
            print(‘%s:%s [%s]‘ %(addr[0],addr[1],data))
            if not data:break
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()
if __name__ == ‘__main__‘:
    server(‘127.0.0.1‘,8092)

客户端:

from threading import Thread
from socket import *

def client():
    c=socket(AF_INET,SOCK_STREAM)
    c.connect((‘127.0.0.1‘,8092))

    while True:
        c.send(‘hello‘.encode(‘utf-8‘))
        data=c.recv(1024)
        print(data.decode(‘utf-8‘))

if __name__ == ‘__main__‘:
    for i in range(500):
        t=Thread(target=client)
        t.start()

 基于协程实现网络爬虫:

from gevent import monkey;monkey.patch_all()
import gevent
import requests
from threading import current_thread
def get(url):
    print(‘%s get %s‘ %(current_thread().getName(),url))
    response=requests.get(url)
    if response.status_code == 200:
        return {‘url‘:len(response.text)}
        # print({‘url‘:len(response.text)})


g1=gevent.spawn(get,‘http://www.baidu.com‘)
g2=gevent.spawn(get,‘http://www.python.org‘)
g3=gevent.spawn(get,‘http://www.jd.com‘)

g1.join()
g2.join()
g3.join()

print(g1.value)
print(g2.value)
print(g3.value)

 

   

重修课程day35(网络编程九之协程)

标签:serve   迭代   word   join()   .com   day   pytho   eset   ret   

原文地址:http://www.cnblogs.com/fangjie0410/p/7684365.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!