协程:微线程 是一种用户态的轻量级线程
使用yiled进行模拟协程
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))
#time.sleep(1)
def producer():
r = con.__next__()
r = con2.__next__()
n = 0
while n < 5:
n += 1
con.send(n) #send 唤醒生成器的同时给他传一个值(就是yield接收到的值)
con2.send(n)
print("\033[32;1m[producer]\033[0m is making baozi %s" %n)
if __name__ == '__main__':
con = consumer("c1") #第一次调用yield 只是生成器 __next__才执行
con2 = consumer("c2")
p = producer()
***********************************运行结果*****************************
"D:\Program Files\Python36\python.exe" D:/untitled/day10/12.py
----->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
Process finished with exit code 0
greenlet
from greenlet import greenlet
def test1():
print(12)
gr2.switch() #跳到test2
print(34)
gr2.switch()
def test2():
print(56)
gr1.switch()
print(78)
gr1 = greenlet(test1) #启动一个协程
gr2 = greenlet(test2)
gr1.switch() #直接运行gr1--->test1
**********************************运行结果*******************************
"D:\Program Files\Python36\python.exe" D:/untitled/day10/协程.py
12
56
34
78
Process finished with exit code 0
Gevent 自动io切换
import gevent
def foo():
print('Running in foo')
gevent.sleep(2) #模仿io操作
print('Explicit context switch to foo again')
def bar():
print('Explicit context to bar')
gevent.sleep(1)
print('Implicit context switch back to bar')
def func3():
print("running func3")
gevent.sleep(0)
print("running func3 again ")
gevent.joinall([
gevent.spawn(foo), #生成一个协程
gevent.spawn(bar),
gevent.spawn(func3),
])
************************************运行结果*************************************
"D:\Program Files\Python36\python.exe" D:/untitled/day10/出现io就自动切换.py
Running in foo
Explicit context to bar
running func3
running func3 again
Implicit context switch back to bar
Explicit context switch to foo again
Process finished with exit code 0
同步与异步的性能区别
import gevent
def task(pid):
"""
Some non-deterministic task
"""
gevent.sleep(0.5)
print('Task %s done' % pid)
def synchronous():
for i in range(1,10):
task(i)
def asynchronous():
threads = [gevent.spawn(task, i) for i in range(10)]
gevent.joinall(threads)
print('Synchronous:')
synchronous()
print('Asynchronous:')
asynchronous()
**********************************运行结果********************************
"D:\Program Files\Python36\python.exe" D:/python_work/day10/同步与异步的区别.py
Synchronous:
Task 1 done
Task 2 done
Task 3 done
Task 4 done
Task 5 done #串行
Task 6 done
Task 7 done
Task 8 done
Task 9 done
Asynchronous:
Task 0 done
Task 1 done
Task 2 done
Task 3 done #并行
Task 4 done
Task 5 done
Task 6 done
Task 7 done
Task 8 done
Task 9 done
Process finished with exit code 0
遇到IO阻塞时会自动切换任务
from urllib import request
import gevent,time #gevent默认检测不到urllib的io操作
from gevent import monkey #要让gevent知道urllib执行了
monkey.patch_all() #把当前程序的所有的io操作给我单独的做上标记
def f(url):
print('GET: %s' % url)
resp = request.urlopen(url)
data = resp.read()
print('%d bytes received from %s.' % (len(data), url))
urls = ['https://www.baidu.com/',
'https://www.cnblogs.com/',
'https://www.csdn.net/'
]
time_start = time.time()
for url in urls:
f(url)
print("同步cost",time.time() - time_start)
async_time_start = time.time()
gevent.joinall([
gevent.spawn(f,'https://www.baidu.com/'),
gevent.spawn(f, 'https://www.cnblogs.com/'),
gevent.spawn(f, 'https://www.csdn.net/'),
])
print("异步cost", time.time() - async_time_start)
**************************运行结果**************************
"D:\Program Files\Python36\python.exe" D:/python_work/day10/爬虫.py
GET: https://www.baidu.com/
227 bytes received from https://www.baidu.com/.
GET: https://www.cnblogs.com/
75222 bytes received from https://www.cnblogs.com/.
GET: https://www.csdn.net/
1157134 bytes received from https://www.csdn.net/.
同步cost 1.954352855682373
GET: https://www.baidu.com/
GET: https://www.cnblogs.com/
GET: https://www.csdn.net/
227 bytes received from https://www.baidu.com/.
75222 bytes received from https://www.cnblogs.com/.
1154974 bytes received from https://www.csdn.net/.
异步cost 0.9943621158599854
Process finished with exit code 0
通过gevent实现单线程下的多socket并发
server side
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(500)
while True:
cli, addr = s.accept()
gevent.spawn(handle_request, cli) #起一个协程
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 ex: #打印异常
print(ex)
finally:
conn.close()
if __name__ == '__main__':
server(8001)
client side
import socket
HOST = 'localhost'
PORT = 8001
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:
msg = bytes(input(">>:"),encoding="utf-8")
s.sendall(msg)
data = s.recv(1024)
print('Received', repr(data)) #repr格式化输出
s.close()