协程

 协程,自己控制cpu在多任务中切换,即单线程实现并发任务。单线程无法实现并行,但可实现并发。

协程:是一种用户态的轻量级线程,即协程是由用户程序自己控制调度。

优点:

切换开销更小

单线程内可以实现并发效果,最大限度利用cpu

缺点:

协程无法利用多核

协程为单个线程,一旦阻塞则阻塞整个线程

总结:

必须在只有一个单线程里实现并发

修改数据不用加锁

用户程序里自己保存多个控制流的上下文栈

yeild实现纯计算对比:

#并发
def producer():
    g=consumer()
    next(g)
    for i in range(10000):
        print("producer")
        g.send(i)

def consumer():
    while True:
        res=yield
        print("consumer")
import time
start_time=time.time()
producer()
print(time.time()-start_time)

#串行
def producer():
    res=[]
    for i in range(10000):
        print("producer")
        res.append(i)

def consumer(res):
    pass
import time
start_time=time.time()
producer()
print(time.time()-start_time)

协程,降低I/O阻塞,提高利用率

 greenlet模块,实现多模块之间切换,多任务I/O密集型使用。

#pip3 install greenlet
from greenlet import greenlet
def eat(name):
    print("%s eat 1" % name)
    g2.switch("ya")
    print("%s eat 2" % name)
    g2.switch()
def play(name):
    print("%s play 1" % name)
    g1.switch()
    print("%s play 2" % name)
    g1.switch()
g1=greenlet(eat)
g2=greenlet(play)
g1.switch("ya")

gevent模块

默认为异步提交

import gevent,time
from gevent import monkey
monkey.patch_all()#监控所有I/O操作,否则只能识别sleep()
def eat(name):
    print("%s eat 1" % name)
    gevent.sleep(3)
    print("%s eat 2" % name)
def play(name):
    print("%s play 1" % name)
    gevent.sleep(5)
    print("%s play 2" % name)
start_time=time.time()
g1=gevent.spawn(eat,"ya")
g2=gevent.spawn(play,"ya")
g1.join()
g2.join()
print(time.time()-start_time)

gevent模块异步提交任务,join(),保证主线程等待任务执行完毕

也可以用joinall()方法

gevent.joinall([g1,g2])

gevent协程实现套接字

 server:

from socket import *
from gevent import monkey,spawn;monkey.patch_all()
def talk(conn):
    print(conn)
    while True:
        try:
            print("recv")
            data=conn.recv(1024)
            if not data:
                break
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()
def server(ip,port):
    server=socket(AF_INET,SOCK_STREAM)
    # server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    server.bind((ip,port))
    server.listen(5)
    while True:
        conn,addr=server.accept()
        spawn(talk,conn)
    server.close()
if __name__ == "__main__":
    g=spawn(server,"127.0.0.1",8080)
    g.join()
View Code

client:

from threading import Thread,currentThread
from socket import *
def client():
    client=socket(AF_INET,SOCK_STREAM)
    client.connect(("127.0.0.1",8080))
    while True:
        client.send(("%s say hello" % currentThread().getName()).encode("utf-8"))
        data=client.recv(1024)
        print(data.decode("utf-8"))
if __name__=="__main__":
    for i in range(500):
        t=Thread(target=client)
        t.start()
View Code
posted @ 2018-05-17 07:33  丫丫625202  阅读(133)  评论(0编辑  收藏  举报