Halo
发布于 2022-05-06 / 91 阅读 / 0 评论 / 0 点赞

python 事件编程

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()

评论