python同步与异步的性能区别及实例
同步与异步的性能区别 1.
#coding:utf-8import 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()#异步 这⾥会按照sleep 设置来执⾏
2.Python通过yield提供了对协程的基本⽀持,但是不完全。⽽第三⽅的gevent为Python提供了⽐较完善的协程⽀持。gevent是第三⽅库,通过greenlet实现协程,其基本思想是:
当⼀个greenlet遇到IO操作时,⽐如访问⽹络,就⾃动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执⾏。由于IO操作⾮常耗时,经常使程序处于等待状态,有了gevent为我们⾃动切换协程,就保证总有greenlet在运⾏,⽽不是等待IO。1.可⽤使⽤gevent.sleep()调整执⾏顺序也可以2.使⽤monkey patch来修改标准库,不改原始代码的⽅式调整。
由于切换是在IO操作时⾃动完成,所以gevent需要修改Python⾃带的⼀些标准库,这⼀过程在启动时通过monkey patch完成:遇到IO阻塞时会⾃动切换任务
#coding:utf-8
from urllib import urlopenimport gevent
from gevent import monkey;monkey.patch_all() #修改标准库,使IO操作时,还会继续执⾏其他的协程def t(n): print n
url=urlopen(n) #遇到IO操作都会⾃动执⾏其他协程 urll=url.read()
print 'len%s,url%s'%(len(urll),n)gevent.joinall([
gevent.spawn(t,'https://www.cnblogs.com/iexperience/p/9342446.html'), gevent.spawn(t,'https://www.cnblogs.com/iexperience/p/9329362.html'), gevent.spawn(t,'https://www.cnblogs.com/iexperience/p/9329332.html'), ])
结果:
从结果看,3个⽹络操作是并发执⾏的,⽽且结束顺序不同,但只有⼀个线程。
要让greenlet交替运⾏,可以通过gevent.sleep()交出控制权,像开始的实例1中的异步⼀样:
通过gevent来实现单线程下的多socket并发
server 端,采⽤gevent协程
import sysimport socketimport timeimport gevent
from gevent import socket,monkeymonkey.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) #gevent.spwan调⽤handle参数并传参
def handle_request(conn): try:
while True:
data = conn.recv(1024) print(\"recv:\ 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端单线程的客户端
import socket
HOST = 'localhost' # The remote host
PORT = 8001 # The same port as used by the servers = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.connect((HOST, PORT))while True:
msg = bytes(input(\">>:\"),encoding=\"utf8\") s.sendall(msg)
data = s.recv(1024) #print(data)
print('Received', repr(data))s.close()
多线程客户端去请求
import socketimport threadingdef sock_conn():
client = socket.socket()
client.connect((\"localhost\ 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()