Skip to content

Commit 092584c

Browse files
committed
Merge branch 'master' of github.com:laixintao/python-parallel-programming-cookbook-cn
2 parents 97794ca + 26fe9df commit 092584c

File tree

3 files changed

+253
-0
lines changed

3 files changed

+253
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# 《Python Parallel Programming Cookbok》翻译计划
22

3+
在线阅读:http://python-parallel-programmning-cookbook.readthedocs.io/ [![Documentation Status](https://readthedocs.org/projects/python-parallel-programmning-cookbook/badge/?version=latest)](http://python-parallel-programmning-cookbook.readthedocs.io/zh_CN/latest/?badge=latest)
4+
35
本书结合Python讨论了线程、进程和异步编程三种模型,是Pyhton并行编程不错的参考书籍。
46

57
目前进度: 10%
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,130 @@
11
使用Asyncio控制任务
22
===================
3+
4+
Asyncio是用来处理事件循环中的异步进程和并发任务执行的。它还提供了 ``asyncio.Task()`` 类,可以在任务中使用协程。它的作用是,在同一事件循环中,运行某一个任务的同时可以并发地运行多个任务。当协程被包在任务中,它会自动将任务和事件循环连接起来,当事件循环启动的时候,任务自动运行。这样就提供了一个可以自动驱动协程的机制。
5+
6+
|ready|
7+
-------
8+
9+
Asyncio模块为我们提供了 ``asyncio.Task(coroutine)`` 方法来处理计算任务,它可以调度协程的执行。任务对协程对象在事件循环的执行负责。如果被包裹的协程要从future yield,那么任务会被挂起,等待future的计算结果。
10+
11+
当future计算完成,被包裹的协程将会拿到future返回的结果或异常(exception)继续执行。另外,需要注意的是,事件循环一次只能运行一个任务,除非还有其它事件循环在不同的线程并行运行,此任务才有可能和其他任务并行。当一个任务在等待future执行的期间,事件循环会运行一个新的任务。 ::
12+
13+
"""
14+
Asyncio using Asyncio.Task to execute three math function in parallel
15+
"""
16+
import asyncio
17+
@asyncio.coroutine
18+
def factorial(number):
19+
f = 1
20+
for i in range(2, number + 1):
21+
print("Asyncio.Task: Compute factorial(%s)" % (i))
22+
yield from asyncio.sleep(1)
23+
f *= i
24+
print("Asyncio.Task - factorial(%s) = %s" % (number, f))
25+
26+
@asyncio.coroutine
27+
def fibonacci(number):
28+
a, b = 0, 1
29+
for i in range(number):
30+
print("Asyncio.Task: Compute fibonacci (%s)" % (i))
31+
yield from asyncio.sleep(1)
32+
a, b = b, a + b
33+
print("Asyncio.Task - fibonacci(%s) = %s" % (number, a))
34+
35+
@asyncio.coroutine
36+
def binomialCoeff(n, k):
37+
result = 1
38+
for i in range(1, k+1):
39+
result = result * (n-i+1) / i
40+
print("Asyncio.Task: Compute binomialCoeff (%s)" % (i))
41+
yield from asyncio.sleep(1)
42+
print("Asyncio.Task - binomialCoeff(%s , %s) = %s" % (n, k, result))
43+
44+
if __name__ == "__main__":
45+
tasks = [asyncio.Task(factorial(10)),
46+
asyncio.Task(fibonacci(10)),
47+
asyncio.Task(binomialCoeff(20, 10))]
48+
loop = asyncio.get_event_loop()
49+
loop.run_until_complete(asyncio.wait(tasks))
50+
loop.close()
51+
52+
|how|
53+
-----
54+
55+
在下面的代码中,我们展示了三个可以被 ``Asyncio.Task()`` 并发执行的数学函数。
56+
57+
58+
运行的结果如下: ::
59+
60+
python3 task.py
61+
Asyncio.Task: Compute factorial(2)
62+
Asyncio.Task: Compute fibonacci (0)
63+
Asyncio.Task: Compute binomialCoeff (1)
64+
Asyncio.Task: Compute factorial(3)
65+
Asyncio.Task: Compute fibonacci (1)
66+
Asyncio.Task: Compute binomialCoeff (2)
67+
Asyncio.Task: Compute factorial(4)
68+
Asyncio.Task: Compute fibonacci (2)
69+
Asyncio.Task: Compute binomialCoeff (3)
70+
Asyncio.Task: Compute factorial(5)
71+
Asyncio.Task: Compute fibonacci (3)
72+
Asyncio.Task: Compute binomialCoeff (4)
73+
Asyncio.Task: Compute factorial(6)
74+
Asyncio.Task: Compute fibonacci (4)
75+
Asyncio.Task: Compute binomialCoeff (5)
76+
Asyncio.Task: Compute factorial(7)
77+
Asyncio.Task: Compute fibonacci (5)
78+
Asyncio.Task: Compute binomialCoeff (6)
79+
Asyncio.Task: Compute factorial(8)
80+
Asyncio.Task: Compute fibonacci (6)
81+
Asyncio.Task: Compute binomialCoeff (7)
82+
Asyncio.Task: Compute factorial(9)
83+
Asyncio.Task: Compute fibonacci (7)
84+
Asyncio.Task: Compute binomialCoeff (8)
85+
Asyncio.Task: Compute factorial(10)
86+
Asyncio.Task: Compute fibonacci (8)
87+
Asyncio.Task: Compute binomialCoeff (9)
88+
Asyncio.Task - factorial(10) = 3628800
89+
Asyncio.Task: Compute fibonacci (9)
90+
Asyncio.Task: Compute binomialCoeff (10)
91+
Asyncio.Task - fibonacci(10) = 55
92+
Asyncio.Task - binomialCoeff(20 , 10) = 184756.0
93+
94+
|work|
95+
------
96+
97+
在这个例子中,我们定义了三个协程, ``factorial``, ``fibonacci`` 和 ``binomialCoeff`` ,每一个都带有 ``asyncio.coroutine`` 装饰器: ::
98+
99+
@asyncio.coroutine
100+
def factorial(number):
101+
do Something
102+
103+
@asyncio.coroutine
104+
def fibonacci(number):
105+
do Something
106+
107+
@asyncio.coroutine
108+
def binomialCoeff(n, k):
109+
do Something
110+
111+
为了能并行执行这三个任务,我们将其放到一个task的list中: ::
112+
113+
if __name__ == "__main__":
114+
tasks = [asyncio.Task(factorial(10)),
115+
asyncio.Task(fibonacci(10)),
116+
asyncio.Task(binomialCoeff(20, 10))]
117+
118+
得到事件循环: ::
119+
120+
loop = asyncio.get_event_loop()
121+
122+
然后运行任务: ::
123+
124+
loop.run_until_complete(asyncio.wait(tasks))
125+
126+
这里, ``asyncio.wait(tasks)`` 表示运行直到所有给定的协程都完成。
127+
128+
最后,关闭事件循环: ::
129+
130+
loop.close()
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,125 @@
11
使用Asyncio和Futures
22
====================
3+
4+
Asyncio 模块的另一个重要的组件是 ``Future`` 类。它和 ``concurrent.futures.Futures`` 很像,但是针对Asyncio的事件循环做了很多定制。 ``asyncio.Futures`` 类代表还未完成的结果(有可能是一个Exception)。所以综合来说,它是一种抽象,代表还没有做完的事情。
5+
6+
实际上,必须处理一些结果的回调函数被加入到了这个类的实例中。
7+
8+
|ready|
9+
-------
10+
11+
要操作Asyncio中的 ``Future`` ,必须进行以下声明: ::
12+
13+
import asyncio
14+
future = asyncio.Future()
15+
16+
基本的方法有:
17+
18+
- ``cancel()``: 取消future的执行,调度回调函数
19+
- ``result()``: 返回future代表的结果
20+
- ``exception()``: 返回future中的Exception
21+
- ``add_done_callback(fn)``: 添加一个回调函数,当future执行的时候会调用这个回调函数
22+
- ``remove_done_callback(fn)``: 从“call whten done”列表中移除所有callback的实例
23+
- ``set_result(result)``: 将future标为执行完成,并且设置result的值
24+
- ``set_exception(exception)``: 将future标为执行完成,并设置Exception
25+
26+
|how|
27+
-----
28+
29+
下面的例子展示了 ``Future`` 类是如何管理两个协程的,第一个协程 ``first_coroutine`` 计算前n个数的和, 第二个协程 ``second_coroutine`` 计算n的阶乘,代码如下: ::
30+
31+
# -*- coding: utf-8 -*-
32+
33+
"""
34+
Asyncio.Futures - Chapter 4 Asynchronous Programming
35+
"""
36+
import asyncio
37+
import sys
38+
39+
@asyncio.coroutine
40+
def first_coroutine(future, N):
41+
"""前n个数的和"""
42+
count = 0
43+
for i in range(1, N + 1):
44+
count = count + i
45+
yield from asyncio.sleep(4)
46+
future.set_result("first coroutine (sum of N integers) result = " + str(count))
47+
48+
@asyncio.coroutine
49+
def second_coroutine(future, N):
50+
count = 1
51+
for i in range(2, N + 1):
52+
count *= i
53+
yield from asyncio.sleep(3)
54+
future.set_result("second coroutine (factorial) result = " + str(count))
55+
56+
def got_result(future):
57+
print(future.result())
58+
59+
if __name__ == "__main__":
60+
N1 = int(sys.argv[1])
61+
N2 = int(sys.argv[2])
62+
loop = asyncio.get_event_loop()
63+
future1 = asyncio.Future()
64+
future2 = asyncio.Future()
65+
tasks = [
66+
first_coroutine(future1, N1),
67+
second_coroutine(future2, N2)]
68+
future1.add_done_callback(got_result)
69+
future2.add_done_callback(got_result)
70+
loop.run_until_complete(asyncio.wait(tasks))
71+
loop.close()
72+
73+
输出如下: ::
74+
75+
$ python asy.py 1 1
76+
first coroutine (sum of N integers) result = 1
77+
second coroutine (factorial) result = 1
78+
$ python asy.py 2 2
79+
first coroutine (sum of N integers) result = 3
80+
second coroutine (factorial) result = 2
81+
$ python asy.py 3 3
82+
first coroutine (sum of N integers) result = 6
83+
second coroutine (factorial) result = 6
84+
$ python asy.py 4 4
85+
first coroutine (sum of N integers) result = 10
86+
second coroutine (factorial) result = 24
87+
88+
|work|
89+
------
90+
91+
在主程序中,我们通过定义future对象和协程联系在一起: ::
92+
93+
if __name__ == "__main__":
94+
...
95+
future1 = asyncio.Future()
96+
future2 = asyncio.Future()
97+
98+
定义tasks的时候,将future对象作为变量传入协程中: ::
99+
100+
tasks = [
101+
first_coroutine(future1, N1),
102+
second_coroutine(future2, N2)]
103+
104+
最后,添加一个 ``future`` 执行时的回调函数: ::
105+
106+
def got_result(future):
107+
print(future.result())
108+
109+
在我们传入future的协程中,在计算之后我们分别添加了3s、4s的睡眠时间: ::
110+
111+
yield from asyncio.sleep(4)
112+
113+
然后,我们将future标为完成,通过 ``future.set_result()`` 设置结果。
114+
115+
|more|
116+
------
117+
118+
交换两个协程睡眠的时间,协程2会比1更早得到结果: ::
119+
120+
$ python asy.py 3 3
121+
second coroutine (factorial) result = 6
122+
first coroutine (sum of N integers) result = 6
123+
$ python asy.py 4 4
124+
second coroutine (factorial) result = 24
125+
first coroutine (sum of N integers) result = 10

0 commit comments

Comments
 (0)