您的位置:首页 > 理论基础 > 计算机网络

python网络编程-协程(协程说明,greenlet,gevent)

2017-07-01 19:42 549 查看

一:什么是协程

  协程(Coroutine):,又称微线程。协程是一种用户态的轻量级线程。是由用户自己控制,CPU根本不知道协程存在。

  协程拥有自己的寄存器上下文和栈。

  协程调度切换时,将寄存器上下文和栈保存在其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈

  因此:协程能保留上一次调用的时的状态,每次过程重入时,就相当于进入上一次调用的。

  换种说法:进入上一次离开时所处逻辑流的位置。

  注意:线程切换会保存到CPU的寄存器里。

  协程的标准:

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

  2)修改共享数据不需要加锁

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

  4)一个协程遇到IO操作自动切换到其他协程

  

二:协程在什么时候切换

  在什么时候进程切换:遇到I/O操作就切换,协程就是把io踢掉了(因为IO耗时)。

   什么时候切回去: I0操作调用完了,通过调用callback切换回去

 

三:协程的优点缺点

  优点:

  1)无需线程上下文切换的开销

  2)无需原子操作锁定及同步的开销(因为协程就是单线程,它就是串行,同一时间改数据只有一个线程)

  3)方便切换控制流,简化编程模型

  4)高并发+高扩展性+低成本:一个CPU支持上万的协程不是问题,很适合高并发

  缺点:

  1)无法利用多核资源:协程本质是单线程,他不能同时单个CPU的多个核用上,协程需要和进程配合

    才能运行在多CPU上。

  2)进行阻塞(Blocking)操作(如IO时)会阻塞整个程序

 

 

四:yield实现切换

  

# -*- coding:utf-8 -*-
__author__ = 'shisanjun'

import time
import queue

def consumer(name):
print("------->starting eating baozi...")

while True:
new_baozi=yield
print("[%s] is eating baozi %s" %(name,new_baozi))

def producer():
r=con.__next__() #con=consumer("c1")#只是生成生成器,不会执行,所以先要调用next才会开始执行
r=con2.__next__()

n=0

while n <5:
n+=1
con.send(n)#两个作业,唤醒生成器,并赋值
con2.send(n)

print("\033[32;1m[producer]\033[0m is making baozi %s" %n)

if __name__=='__main__':
con=consumer("c1") #生成生成器
con2=consumer("c2")
p=producer()

"""
------->starting eating baozi...
------->starting eating baozi...
[c1] is eating baozi 1
[c2] is eating baozi 1
[producer] is making baozi 1
[c1] is eating baozi 2
[c2] is eating baozi 2
[producer] is making baozi 2
[c1] is eating baozi 3
[c2] is eating baozi 3
[producer] is making baozi 3
[c1] is eating baozi 4
[c2] is eating baozi 4
[producer] is making baozi 4
[c1] is eating baozi 5
[c2] is eating baozi 5
[producer] is making baozi 5
"""

  我们刚才用yield实现一个简单的协程,实现单线程多并发。

 

 

五:Greenlet

  greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator

  

# -*- coding:utf-8 -*-
__author__ = 'shisanjun'

from greenlet import greenlet

def test1():
print(12)
gr2.switch()
print(34)
gr2.switch()

def test2():
print(56)
gr1.switch()
print(78)

gr1=greenlet(test1)#起动一个协程
gr2=greenlet(test2)
gr1.switch() #从test1开始

 

  上面代码切换过程

  

# -*- coding:utf-8 -*-
__author__ = 'shisanjun'
import sys
import socket
import time
import gevent

from gevent import socket,monkey

monkey.patch_all()

def server(port):
s=socket.socket()
s.bind(("0.0.0.0",port))
s.listen(100)

while True:
conn,addr=s.accept()
gevent.spawn(handle_request,conn)

def   handle_request(conn):
try:
while True:
data=conn.recv(1024)
print('recv:',data)
conn.send(data)
if not data:
conn.shutdown(socket.SHUT_WR)
except Exception as e:
print(e)
finally:
conn.close()

if __name__=="__main__":
server(8001)
View Code
# -*- coding:utf-8 -*-
__author__ = 'shisanjun'
import socket
import threading

def sock_conn():

client = socket.socket()

client.connect(("localhost",8001))
count = 0
while True:
#msg = input(">>:").strip()
#if len(msg) == 0:continue
client.send( ("hello %s" %count).encode("utf-8"))

data = client.recv(1024)

print("[%s]recv from server:" % threading.get_ident(),data.decode()) #结果
count +=1
client.close()

for i in range(100):
t = threading.Thread(target=sock_conn)
t.start()

#并发100个sock连接
View Code  

本文没有解决:什么时候切换回来

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: