|
5 | 5 | ----------
|
6 | 6 | 问题
|
7 | 7 | ----------
|
8 |
| -You are running multiple instances of the Python interpreter, possibly on different ma‐ |
9 |
| -chines, and you would like to exchange data between interpreters using messages. |
| 8 | +你在不同的机器上面运行着多个Python解释器实例,并希望能够在这些解释器之间通过消息来交换数据。 |
10 | 9 |
|
11 | 10 | |
|
12 | 11 |
|
13 | 12 | ----------
|
14 | 13 | 解决方案
|
15 | 14 | ----------
|
16 |
| -It is easy to communicate between interpreters if you use the multiprocessing.con |
17 |
| -nection module. Here is a simple example of writing an echo server: |
| 15 | +通过使用 ``multiprocessing.connection`` 模块可以很容易的实现解释器之间的通信。 |
| 16 | +下面是一个简单的应答服务器例子: |
18 | 17 |
|
19 |
| -from multiprocessing.connection import Listener |
20 |
| -import traceback |
| 18 | +.. code-block:: python |
21 | 19 |
|
22 |
| -def echo_client(conn): |
23 |
| - try: |
24 |
| - while True: |
25 |
| - msg = conn.recv() |
26 |
| - conn.send(msg) |
27 |
| - except EOFError: |
28 |
| - print('Connection closed') |
29 |
| - |
30 |
| -def echo_server(address, authkey): |
31 |
| - serv = Listener(address, authkey=authkey) |
32 |
| - while True: |
| 20 | + from multiprocessing.connection import Listener |
| 21 | + import traceback |
| 22 | +
|
| 23 | + def echo_client(conn): |
33 | 24 | try:
|
34 |
| - client = serv.accept() |
35 |
| - |
36 |
| - echo_client(client) |
37 |
| - except Exception: |
38 |
| - traceback.print_exc() |
39 |
| - |
40 |
| -echo_server(('', 25000), authkey=b'peekaboo') |
41 |
| - |
42 |
| -Here is a simple example of a client connecting to the server and sending various |
43 |
| -messages: |
44 |
| - |
45 |
| ->>> from multiprocessing.connection import Client |
46 |
| ->>> c = Client(('localhost', 25000), authkey=b'peekaboo') |
47 |
| ->>> c.send('hello') |
48 |
| ->>> c.recv() |
49 |
| -'hello' |
50 |
| ->>> c.send(42) |
51 |
| ->>> c.recv() |
52 |
| -42 |
53 |
| ->>> c.send([1, 2, 3, 4, 5]) |
54 |
| ->>> c.recv() |
55 |
| -[1, 2, 3, 4, 5] |
56 |
| ->>> |
57 |
| - |
58 |
| -Unlike a low-level socket, messages are kept intact (each object sent using send() is |
59 |
| -received in its entirety with recv()). In addition, objects are serialized using pickle. |
60 |
| -So, any object compatible with pickle can be sent or received over the connection. |
| 25 | + while True: |
| 26 | + msg = conn.recv() |
| 27 | + conn.send(msg) |
| 28 | + except EOFError: |
| 29 | + print('Connection closed') |
| 30 | +
|
| 31 | + def echo_server(address, authkey): |
| 32 | + serv = Listener(address, authkey=authkey) |
| 33 | + while True: |
| 34 | + try: |
| 35 | + client = serv.accept() |
| 36 | +
|
| 37 | + echo_client(client) |
| 38 | + except Exception: |
| 39 | + traceback.print_exc() |
| 40 | +
|
| 41 | + echo_server(('', 25000), authkey=b'peekaboo') |
| 42 | +
|
| 43 | +然后客户端连接服务器并发送消息的简单示例: |
| 44 | + |
| 45 | +.. code-block:: python |
| 46 | +
|
| 47 | + >>> from multiprocessing.connection import Client |
| 48 | + >>> c = Client(('localhost', 25000), authkey=b'peekaboo') |
| 49 | + >>> c.send('hello') |
| 50 | + >>> c.recv() |
| 51 | + 'hello' |
| 52 | + >>> c.send(42) |
| 53 | + >>> c.recv() |
| 54 | + 42 |
| 55 | + >>> c.send([1, 2, 3, 4, 5]) |
| 56 | + >>> c.recv() |
| 57 | + [1, 2, 3, 4, 5] |
| 58 | + >>> |
| 59 | +
|
| 60 | +跟底层socket不同的是,每个消息会完整保存(每一个通过send()发送的对象能通过recv()来完整接受)。 |
| 61 | +另外,所有对象会通过pickle序列化。因此,任何兼容pickle的对象都能在此连接上面被发送和接受。 |
61 | 62 |
|
62 | 63 | |
|
63 | 64 |
|
64 | 65 | ----------
|
65 | 66 | 讨论
|
66 | 67 | ----------
|
67 |
| -There are many packages and libraries related to implementing various forms of mes‐ |
68 |
| -sage passing, such as ZeroMQ, Celery, and so forth. As an alternative, you might also |
69 |
| -be inclined to implement a message layer on top of low-level sockets. However, some‐ |
70 |
| -times you just want a simple solution. The multiprocessing.connection library is just |
71 |
| -that—using a few simple primitives, you can easily connect interpreters together and |
72 |
| -have them exchange messages. |
73 |
| -If you know that the interpreters are going to be running on the same machine, you can |
74 |
| -use alternative forms of networking, such as UNIX domain sockets or Windows named |
75 |
| -pipes. To create a connection using a UNIX domain socket, simply change the address |
76 |
| -to a filename such as this: |
77 |
| - |
78 |
| -s = Listener('/tmp/myconn', authkey=b'peekaboo') |
79 |
| - |
80 |
| -To create a connection using a Windows named pipe, use a filename such as this: |
81 |
| - |
82 |
| -s = Listener(r'\\.\pipe\myconn', authkey=b'peekaboo') |
83 |
| - |
84 |
| -As a general rule, you would not be using multiprocessing to implement public-facing |
85 |
| -services. The authkey parameter to Client() and Listener() is there to help authen‐ |
86 |
| -ticate the end points of the connection. Connection attempts with a bad key raise an |
87 |
| -exception. In addition, the module is probably best suited for long-running connections |
88 |
| - |
89 |
| -(not a large number of short connections). For example, two interpreters might establish |
90 |
| -a connection at startup and keep the connection active for the entire duration of a |
91 |
| -problem. |
92 |
| -Don’t use multiprocessing if you need more low-level control over aspects of the con‐ |
93 |
| -nection. For example, if you needed to support timeouts, nonblocking I/O, or anything |
94 |
| -similar, you’re probably better off using a different library or implementing such features |
95 |
| -on top of sockets instead. |
| 68 | +目前有很多用来实现各种消息传输的包和函数库,比如ZeroMQ、Celery等。 |
| 69 | +你还有另外一种选择就是自己在底层socket基础之上来实现一个消息传输层。 |
| 70 | +但是你想要简单一点的方案,那么这时候 ``multiprocessing.connection`` 就派上用场了。 |
| 71 | +仅仅使用一些简单的语句即可实现多个解释器之间的消息通信。 |
| 72 | + |
| 73 | +如果你的解释器运行在同一台机器上面,那么你可以使用另外的通信机制,比如Unix域套接字或者是Windows命名管道。 |
| 74 | +要想使用UNIX域套接字来创建一个连接,只需简单的将地址改写一个文件名即可: |
| 75 | + |
| 76 | +.. code-block:: python |
| 77 | +
|
| 78 | + s = Listener('/tmp/myconn', authkey=b'peekaboo') |
| 79 | +
|
| 80 | +要想使用Windows命名管道来创建连接,只需像下面这样使用一个文件名: |
| 81 | + |
| 82 | +.. code-block:: python |
| 83 | +
|
| 84 | + s = Listener(r'\\.\pipe\myconn', authkey=b'peekaboo') |
| 85 | +
|
| 86 | +一个通用准则是,你不要使用 ``multiprocessing`` 来实现一个对外的公共服务。 |
| 87 | +``Client()`` 和 ``Listener()`` 中的 ``authkey`` 参数用来认证发起连接的终端用户。 |
| 88 | +如果密钥不对会产生一个异常。此外,该模块最适合用来建立长连接(而不是大量的短连接), |
| 89 | +例如,两个解释器之间启动后就开始建立连接并在处理某个问题过程中会一直保持连接状态。 |
| 90 | + |
| 91 | +如果你需要对底层连接做更多的控制,比如需要支持超时、非阻塞I/O或其他类似的特性, |
| 92 | +你最好使用另外的库或者是在高层socket上来实现这些特性。 |
0 commit comments