PyStdLib--multiprocessing

multiprocessing 与 threading.Thread 类似

multiprocessing.Process 创建进程, 该进程可以运行用 python 编写的函数.

1
2
3
4
5
multiprocessing.Process.start()
multiprocessing.Process.run()
multiprocessing.Process.join()

Process.PID 保存有 PID, 如果进程还没有 start() , 则 PID 为 None.

注意

  • 在 UNIX 平台上, 当某一个进程终止之后, 该进程需要被其父进程调用 wait , 否则进程就成为 僵尸进程. 所以, 需要对每个 Process 对象调用 join() 方法(等同于 wait), 对于多线程来说, 由于只有一个进程, 所以不存在次必要性.

  • multiprocessing 提供了 threading 中没有的 IPC (比如 Queue,Pipe), 效率上更高. 应有限考虑 Pipe 和 Queue, 避免使用 Lock/Event/Semaphore/Condition 等同步方式(应为他们占据的不是用户进程的资源).

  • 多进程应该避免共享资源. 在多线程中, 我们可以比较容易的共享资源, 比如使用全局变量或传递参数. 在多进程情况下, 由于每个进程有自己独立的内存空间, 以上方法并不合适. 此时我们可以通过共享内存和 Manager 的方法来共享资源. 但这样做提高了程序的复杂度, 并因为同步的需要而降低了程序的效率.

示例代码

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/usr/local/bin/env python
#

import os
import threading
import multiprocessing

def worker(sign,lock):
lock.acquire()
print(sign,os.getpid())
lock.release()

print("main:",os.getpid())

# multi-thread
record=[]

lock = threading.Lock()
for i in range(5):
thread = threading.Thread(target=worker,args=('thread',lock))
thread.start()
record.append(thread)

for thread in record:
thread.join()

# multi-process
record = []
lock = multiprocessing.Lock()

for i in range(5):
process = multiprocessing.Process(target=worker,args=('process',lock))
process.start()
record.append(process)

for process in record:
process.join()

输出 : 所有 Thread 的 PID 都与主程序相同, 而每个 Process都有一个不同的 PID.

('main:', 105748)
('thread', 105748)
('thread', 105748)
('thread', 105748)
('thread', 105748)
('thread', 105748)
('process', 105754)
('process', 105756)
('process', 105758)
('process', 105755)
('process', 105757)

multiprocessing.Lock

multiprocessing.Event

multiprocessing.Semaphore

multiprocessing.Condition

multiprocessing.Pipe()

1
2
3
4
multiprocessing.Pipe()  # 默认创建双向管道, 该对象返回一个包含两个元素的表, 每个元素代表 Pipe 的一端(Connection对象). 可以在一端调用 send() 方法, 另一端调用 recv() 方法, 实现通信.
multiprocessing.Pipe(duplex=False) # 创建单向管道
multiprocessing.Pipe().send()
multiprocessing.Pipe().recv()

示例代码:

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
#!/usr/local/bin/env python
#

import multiprocessing as mul

def proc1(pipe):
pipe.send('hello')
print('proc1 rec:',pipe.recv())

def proc2(pipe):
print('proc2 rec:',pipe.recv())
pipe.send('hello, too')

# Build a pipe
pipe = mul.Pipe()

# Pass an end of the pipe to process 1
p1 = mul.Process(target=proc1, args=(pipe[0],))
# Pass the other end of the pipe to process 2
p2 = mul.Process(target=proc2, args=(pipe[1],))
p1.start()
p2.start()
p1.join()
p2.join()

输出:
('proc2 rec:', 'hello')
('proc1 rec:', 'hello ,too!')

multiprocessing.Queue 是先进先出的结构. Queue 允许多个进程放入, 多个进程从队列取出对象.

1
2
3
4
mutiprocessing.Queue(maxsize)   创建队列, maxsize 表示队列中可以存放对象的最大数量.

mutiprocessing.Queue(maxsize).put()
mutiprocessing.Queue(maxsize).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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#!/usr/local/bin/env python
#


import os
import multiprocessing
import time

# input worker
def inputQ(queue):
info = str(os.getpid()) + '(put):' + str(time.time())
queue.put(info)

# output worker
def outputQ(queue,lock):
info = queue.get()
lock.acquire()
print (str(os.getpid()) + '(get):' + info)
lock.release()

# Main
record1 = [] # store input processes
record2 = [] # store output processes
lock = multiprocessing.Lock() # To prevent messy print
queue = multiprocessing.Queue(3)

# input processes
for i in range(10):
process = multiprocessing.Process(target=inputQ,args=(queue,))
process.start()
record1.append(process)

# output processes
for i in range(10):
process = multiprocessing.Process(target=outputQ,args=(queue,lock))
process.start()
record2.append(process)

for p in record1:
p.join()

queue.close() # No more object will come, close the queue

for p in record2:
p.join()

输出:
105880(get):105865(put):1488439837.07
105883(get):105866(put):1488439837.07
105879(get):105867(put):1488439837.08
105884(get):105870(put):1488439837.08
105877(get):105873(put):1488439837.08
105885(get):105871(put):1488439837.08
105886(get):105874(put):1488439837.09
105878(get):105872(put):1488439837.08
105881(get):105868(put):1488439837.08
105887(get):105876(put):1488439837.09

multiprocessing.Pool(num) # num 表示创建的进程数.

1
2
3
4
5
6
multiprocessing.Pool(num)       # 创建进程池, 
multiprocessing.Pool(num).map() # 与 map() 函数类似.
multiprocessing.Pool(num).apply_async(func,args) # 从进程池中取出一个进程执行 func, args 为 func 的参数. 他将返回一个 AsyncResult 的对象, 可以对该对象调用 get() 方法, 获取结果.
multiprocessing.Pool(num).apply_async(func,args).get()
multiprocessing.Pool(num).close() # 进程池不再创建新的进程
multiprocessing.Pool(num).join() # wait 进程池的全部进程, 必须对 Pool 先调用 close() 方法, 才能 join.

示例代码:

1
2
3
4
5
6
7
8
9
10
11
import multiprocessing as mul

def f(x):
return x**2

pool = mul.Pool(5)
rel = pool.map(f,[1,2,3,4,5,6,7,8,9,10])
print(rel)

输出:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

共享内存

1
2
multiprocessing.Value(key,value)    # 双精度数数字
multiprocessing.Array(key,value_list) # 数组

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import multiprocessing

def f(n, a):
n.value = 3.14
a[0] = 5

num = multiprocessing.Value('d', 0.0)
arr = multiprocessing.Array('i', range(10))

p = multiprocessing.Process(target=f, args=(num, arr))
p.start()
p.join()

print num.value
print arr[:]

输出:
3.14
[5, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Manager

1
2
3
4
5
6
7
s = multiprocessing.Manager()

s.address s.dict s.list s.register s.Value
s.Array s.Event s.Lock s.RLock
s.BoundedSemaphore s.get_server s.Namespace s.Semaphore
s.Condition s.join s.Pool s.shutdown
s.connect s.JoinableQueue s.Queue s.start

代码示例

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 multiprocessing

def f(x, arr, l):
x.value = 3.14
arr[0] = 5
l.append('Hello')

server = multiprocessing.Manager()
x = server.Value('d', 0.0)
arr = server.Array('i', range(10))
l = server.list()

proc = multiprocessing.Process(target=f, args=(x, arr, l))
proc.start()
proc.join()

print(x.value)
print(arr)
print(l)

输出结果:
3.14
array('i', [5, 1, 2, 3, 4, 5, 6, 7, 8, 9])
['Hello']