gevent
- gevent是python的一个并发框架,以微线程greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效。
- 运行时的具体流程大概是:
当一个greenlet遇到IO操作时,比如访问网络/睡眠等待,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。同时也因为只有一个线程在执行,会极大的减少上下文切换的成本。
进程,线程, 协程
- 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。
- 线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。
- 协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度
使用
# -*- coding: utf-8 -*-
import gevent
def f1():
for i in range(5):
print 'run func: f1, index: %s ' % i
gevent.sleep(0)
def f2():
for i in range(5):
print 'run func: f2, index: %s ' % i
gevent.sleep(0)
t1 = gevent.spawn(f1)
t2 = gevent.spawn(f2)
gevent.joinall([t1, t2])
给程序打补丁
import gevent
import time
from gevent import monkey
# 打补丁,让gevent框架识别耗时操作,比如:time.sleep,网络请求延时
monkey.patch_all()
# 任务1
def work1(num):
for i in range(num):
print("work1....")
time.sleep(0.2)
# gevent.sleep(0.2)
# 任务1
def work2(num):
for i in range(num):
print("work2....")
time.sleep(0.2)
# gevent.sleep(0.2)
if __name__ == '__main__':
# 创建协程指定对应的任务
g1 = gevent.spawn(work1, 3)
g2 = gevent.spawn(work2, 3)
# 主线程等待协程执行完成以后程序再退出
g1.join()
g2.join()
获取返回结果
g_list = list()
for stock in stocks:
dbname = 'daily_data_sz' if stock[0].endswith('.SZ') else 'daily_data_sh'
# get_daily_data 是一个函数,后边的都是此函数所需参数
g = gevent.spawn(get_daily_data, pro, stock, end_date, dbname, engine)
g_list.append(g) # g是一个Greenlet对象
gevent.joinall(g_list)
for i, g in enumerate(g_list):
print(i)
print(g.value)
设置超时
import gevent
import gevent.monkey
import urllib
gevent.monkey.patch_all()
def test():
#就这么用,7是超时时间,后面的False表示不抛出其他异常了!
with gevent.Timeout(7, False) as timeout:
urllib.urlopen("http://www.twitter.com")
if __name__ == "__main__":
g = gevent.spawn(test)
g.join()