multiprocessing 与 threading.Thread 类似

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

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 的方法来共享资源. 但这样做提高了程序的复杂度, 并因为同步的需要而降低了程序的效率.

示例代码
    #!/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()

multiprocessing.Pipe()  # 默认创建双向管道, 该对象返回一个包含两个元素的表, 每个元素代表 Pipe 的一端(Connection对象). 可以在一端调用 send() 方法, 另一端调用 recv() 方法, 实现通信.
multiprocessing.Pipe(duplex=False)    # 创建单向管道
multiprocessing.Pipe().send()
multiprocessing.Pipe().recv()
示例代码:
#!/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 允许多个进程放入, 多个进程从队列取出对象.

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

mutiprocessing.Queue(maxsize).put()
mutiprocessing.Queue(maxsize).get()
示例代码
#!/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 表示创建的进程数.

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.
示例代码:
    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]

共享内存

multiprocessing.Value(key,value)    # 双精度数数字
multiprocessing.Array(key,value_list)   # 数组
代码示例
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

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
代码示例
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']
04-30 06:09