Python gevent学习笔记-2
在上一篇里面介绍了gevent的最主要的功能,先来来了解一下gevent里面一些更加高级的功能。
事件
事件是一种可以让greenlet进行异步通信的手段。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import geventfrom gevent.event import AsyncResulta = AsyncResult()def setter(): """ After 3 seconds set wake all threads waiting on the value of a. """ gevent.sleep(3) a.set()def waiter(): """ After 3 seconds the get call will unblock. """ a.get() # blocking print 'I live!'gevent.joinall([ gevent.spawn(setter), gevent.spawn(waiter),]) |
AsyncResult 是 event对象的扩展能够让你来发送值并且带有一定延迟。这种功能被成为feature或deferred,当它拿到一个未来的值的引用时,能够在任意安排好的时间内让它起作用。
队列
队列是一个有序的数据集合,通常有 put/get 的操作,这样能让队列在有在有greenletJ进行操作的时候能够进行安全的管理。
例如,如果greenlet从队列中取出了一项数据,那么这份数据就不能被另一个greenlet取出。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import geventfrom gevent.queue import Queuetasks = Queue()def worker(n): while not tasks.empty(): task = tasks.get() print('Worker %s got task %s' % (n, task)) gevent.sleep(0) print('Quitting time!')def boss(): for i in xrange(1,25): tasks.put_nowait(i)gevent.spawn(boss).join()gevent.joinall([ gevent.spawn(worker, 'steve'), gevent.spawn(worker, 'john'), gevent.spawn(worker, 'nancy'),]) |
执行的结果如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
Worker steve got task 1Worker john got task 2Worker nancy got task 3Worker steve got task 4Worker nancy got task 5Worker john got task 6Worker steve got task 7Worker john got task 8Worker nancy got task 9Worker steve got task 10Worker nancy got task 11Worker john got task 12Worker steve got task 13Worker john got task 14Worker nancy got task 15Worker steve got task 16Worker nancy got task 17Worker john got task 18Worker steve got task 19Worker john got task 20Worker nancy got task 21Worker steve got task 22Worker nancy got task 23Worker john got task 24Quitting time!Quitting time!Quitting time! |
队列的 put/get 操作在需要的情况下也可以阻塞程序的执行。
put 和 get 操作都有非阻塞的副本,就是 put_nowait 和 get_nowait。
在下面代码的例子里,运行一个叫boss的方法,同时运行worker方法,并且对队列有一个限制:队列的子项不能超过3个。这个限制意味着 put 操作在队列里面有足够空间之前会阻塞。相反,如果队列里没有任何子项,get操作会阻塞,同时也需要超时的机制,当一个操作在阻塞超过一定时间后会抛出异常。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
import geventfrom gevent.queue import Queue, Emptytasks = Queue(maxsize=3)def worker(n): try: while True: task = tasks.get(timeout=1) # decrements queue size by 1 print('Worker %s got task %s' % (n, task)) gevent.sleep(0) except Empty: print('Quitting time!')def boss(): """ Boss will wait to hand out work until a individual worker is free since the maxsize of the task queue is 3. """ for i in xrange(1,10): tasks.put(i) print('Assigned all work in iteration 1') for i in xrange(10,20): tasks.put(i) print('Assigned all work in iteration 2')gevent.joinall([ gevent.spawn(boss), gevent.spawn(worker, 'steve'), gevent.spawn(worker, 'john'), gevent.spawn(worker, 'bob'),]) |
代码的执行结果如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
Worker steve got task 1Worker john got task 2Worker bob got task 3Worker steve got task 4Worker bob got task 5Worker john got task 6Assigned all work in iteration 1Worker steve got task 7Worker john got task 8Worker bob got task 9Worker steve got task 10Worker bob got task 11Worker john got task 12Worker steve got task 13Worker john got task 14Worker bob got task 15Worker steve got task 16Worker bob got task 17Worker john got task 18Assigned all work in iteration 2Worker steve got task 19Quitting time!Quitting time!Quitting time! |
组和池
组是一个由greenlet组成的集合,并且能够被统一管理。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import geventfrom gevent.pool import Groupdef talk(msg): for i in xrange(3): print(msg)g1 = gevent.spawn(talk, 'bar')g2 = gevent.spawn(talk, 'foo')g3 = gevent.spawn(talk, 'fizz')group = Group()group.add(g1)group.add(g2)group.join()group.add(g3)group.join() |
这在管理一组异步任务的时候会很有用。
Group还提供了一个API来分配成组的greenlet任务,并且通过不同的方法来获取结果。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
import geventfrom gevent import getcurrentfrom gevent.pool import Groupgroup = Group()def hello_from(n): print('Size of group', len(group)) print('Hello from Greenlet %s' % id(getcurrent()))group.map(hello_from, xrange(3))def intensive(n): gevent.sleep(3 - n) return 'task', nprint('Ordered')ogroup = Group()for i in ogroup.imap(intensive, xrange(3)): print(i)print('Unordered')igroup = Group()for i in igroup.imap_unordered(intensive, xrange(3)): print(i) |
执行结果如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Size of group 3Hello from Greenlet 10769424Size of group 3Hello from Greenlet 10770544Size of group 3Hello from Greenlet 10772304Ordered('task', 0)('task', 1)('task', 2)Unordered('task', 2)('task', 1)('task', 0) |
池是用来处理当拥有动态数量的greenlet需要进行并发管理(限制并发数)时使用的。
这在处理大量的网络和IO操作的时候是非常需要的。
|
1
2
3
4
5
6
7
8
9
|
import geventfrom gevent.pool import Poolpool = Pool(2)def hello_from(n): print('Size of pool', len(pool))pool.map(hello_from, xrange(3)) |
|
1
2
3
|
Size of pool 2Size of pool 2Size of pool 1 |
经常在创建gevent驱动程序的时候,整个服务需要围绕一个池的结构来执行。
锁和信号量
信号量是低级别的同步机制,能够让greenlet在执行的时候互相协调并且限制其并发数。信号量暴露了两个方法,acquire 和 release。如果信号量范围变成0,那么它会阻塞住直到另一个greenlet释放它的获得物。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
from gevent import sleepfrom gevent.pool import Poolfrom gevent.coros import BoundedSemaphoresem = BoundedSemaphore(2)def worker1(n): sem.acquire() print('Worker %i acquired semaphore' % n) sleep(0) sem.release() print('Worker %i released semaphore' % n)def worker2(n): with sem: print('Worker %i acquired semaphore' % n) sleep(0) print('Worker %i released semaphore' % n)pool = Pool()pool.map(worker1, xrange(0,2))pool.map(worker2, xrange(3,6)) |
一下是代码的执行结果:
|
1
2
3
4
5
6
7
8
9
10
|
Worker 0 acquired semaphoreWorker 1 acquired semaphoreWorker 0 released semaphoreWorker 1 released semaphoreWorker 3 acquired semaphoreWorker 4 acquired semaphoreWorker 3 released semaphoreWorker 4 released semaphoreWorker 5 acquired semaphoreWorker 5 released semaphore |
如果把信号量的数量限制为1那么它就成为了锁。它经常会在多个greenlet访问相同资源的时候用到。
本地线程
Gevent还能够让你给gevent上下文来指定那些数据是本地的。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import geventfrom gevent.local import localstash = local()def f1(): stash.x = 1 print(stash.x)def f2(): stash.y = 2 print(stash.y) try: stash.x except AttributeError: print("x is not local to f2")g1 = gevent.spawn(f1)g2 = gevent.spawn(f2)gevent.joinall([g1, g2]) |
以下是执行结果:
|
1
2
3
|
12x is not local to f2 |
很多集成了gevent的框架把HTTP的session对象存在gevent 本地线程里面。比如下面的例子:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
from werkzeug.local import LocalProxyfrom werkzeug.wrappers import Requestfrom contextlib import contextmanagerfrom gevent.wsgi import WSGIServer_requests = local()request = LocalProxy(lambda: _requests.request)@contextmanagerdef sessionmanager(environ): _requests.request = Request(environ) yield _requests.request = Nonedef logic(): return "Hello " + request.remote_addrdef application(environ, start_response): status = '200 OK' with sessionmanager(environ): body = logic() headers = [ ('Content-Type', 'text/html') ] start_response(status, headers) return [body]WSGIServer(('', 8000), application).serve_forever() |
子进程
在gevent 1.0版本中,gevent.subprocess 这个库被添加上。这个库能够让子进程相互协调地执行。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import geventfrom gevent.subprocess import Popen, PIPEdef cron(): while True: print "cron" gevent.sleep(0.2)g = gevent.spawn(cron)sub = Popen(['sleep 1; uname'], stdout=PIPE, shell=True)out, err = sub.communicate()g.kill()print out.rstrip() |
执行结果:
|
1
2
3
4
5
6
|
croncroncroncroncronLinux |
Python gevent学习笔记-2的更多相关文章
- Python gevent学习笔记
gevent是Python的一个用于网络IO的函数库,其中应用到了 coroutine(协同程序) 的思想.首先来了解下目前网络框架的几种基本的网络I/O模型: 阻塞式单线程:这是最基本的I/O模型, ...
- 【原】Learning Spark (Python版) 学习笔记(三)----工作原理、调优与Spark SQL
周末的任务是更新Learning Spark系列第三篇,以为自己写不完了,但为了改正拖延症,还是得完成给自己定的任务啊 = =.这三章主要讲Spark的运行过程(本地+集群),性能调优以及Spark ...
- Python Click 学习笔记(转)
原文链接:Python Click 学习笔记 Click 是 Flask 的团队 pallets 开发的优秀开源项目,它为命令行工具的开发封装了大量方法,使开发者只需要专注于功能实现.恰好我最近在开发 ...
- 0003.5-20180422-自动化第四章-python基础学习笔记--脚本
0003.5-20180422-自动化第四章-python基础学习笔记--脚本 1-shopping """ v = [ {"name": " ...
- Python Flask学习笔记之模板
Python Flask学习笔记之模板 Jinja2模板引擎 默认情况下,Flask在程序文件夹中的templates子文件夹中寻找模板.Flask提供的render_template函数把Jinja ...
- Python Flask学习笔记之Hello World
Python Flask学习笔记之Hello World 安装virtualenv,配置Flask开发环境 virtualenv 虚拟环境是Python解释器的一个私有副本,在这个环境中可以安装私有包 ...
- 获取字段唯一值工具- -ArcPy和Python案例学习笔记
获取字段唯一值工具- -ArcPy和Python案例学习笔记 目的:获取某一字段的唯一值,可以作为工具使用,也可以作为函数调用 联系方式:谢老师,135-4855-4328,xiexiaokui# ...
- Python高级学习笔记
Python高级学习笔记,此笔记中包含Linux操作系统.Html+CSS+JS.网络协议等. 所有思维导图为本人亲手所画,请勿用于商用. 大哥们,求点赞哦. 第一天笔记:链接 第二天笔记:链接 第三 ...
- Python入门学习笔记4:他人的博客及他人的学习思路
看其他人的学习笔记,可以保证自己不走弯路.并且一举两得,即学知识又学方法! 廖雪峰:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958 ...
随机推荐
- JS中map、forEach、filter、reduce等Array新增方法的区别
数组在各个编程语言中的重要性不言而喻,但是在之前的JavaScript中数组虽然功能已经很强大,但操作方法并不完善,在ECMAScript5中做了适当的补充. Array.isArray(elemen ...
- 最短路径——Floyd,Dijkstra(王道)
题目描述: 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线 ...
- 终端内容输出的同时保存到文件 tee
突然有这个需求,一查用tee就能实现 用法:tee [选项]... [文件]... 将标准输入复制到每个指定文件,并显示到标准输出. -a, --append 内容追加到给定的文件而非覆盖 -i, - ...
- Acer商祺x4610安装及使用
一年前心血来潮买了部Acer商祺x4610,这两天把它装起来,记录下过程以备忘. 首先装操作系统,我装的是XP,这款电脑比较贴心的是开机时按住F12可以选择光盘还是硬盘启动,就不用到BIOS里面设置启 ...
- 【DP】【单调队列】【NOI2005】瑰丽华尔兹
340. [NOI2005] 瑰丽华尔兹 ★★★ 输入文件:adv1900.in 输出文件:adv1900.out 简单对照 时间限制:1 s 内存限制:128 MB [任务描写叙述] 你跳过华尔兹吗 ...
- Linux学习笔记 (五)关机和重启命令
一.关机命令 1.shutdown命令: shutdown [选项] [时间] 选项: -c:取消前一个关机命令 -h:关机 -r:重启 例:shutdown -r 05:30 & //表 ...
- Python基础之字符串的练习
练习1 #!/usr/bin/python -tt # Copyright 2010 Google Inc. # Licensed under the Apache License, Version ...
- CentOS最常用命令
快捷键.常用命令: 文件和目录:# cd /home 进入 '/home' 目录# cd .. 返回上一级目录# cd ../.. 返回上两级目录# cd - 返回上次所在目录# cp file1 f ...
- word转pdf
很多人在工作经常会遇到word转pdf功能,word转pdf还是比较复杂,网上各种包,如python的各种转换包,其实是存在很多问题 的,尤其是对比较复杂的格式,真正的还的是调用组件来转换,这里介绍的 ...
- RabbitMQ消息队基本概念
RabbitMQ简介 AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计.消息中间件主要用于组件之间的 ...