多线程,进程随笔

多进程之子进程与父进程关系

from multiprocessing import Pool, Process
import time
import os
def info(title):
    print(title)
    print('module name:', __name__)
    print('parent process:', os.getppid())
    print('process id', os.getpid())


def f(name):
    time.sleep(5)
    info('function f')
    print('hello', name)


if __name__ == '__main__':
    info('main line')
    p = Process(target=f, args=('Bob',))
    p.daemon = True  # 设置为守护进程
    p.start()
    p.join()

# 当进程不使用join时,如果p主进程为守护进程,那么f子进程可能还没执行完,p父进程就退出了
# f可能会变成僵尸进程(孤儿), 所以如果希望父进程等待子进程执行完任务再退出,则需要使用join
# 当p主进程不是守护进程时,则p不需要join也会等待子进程执行完才退出

# 为了通常不管需不需要设为守护进程,我们都希望子进程能完成任务,那么每次新建进程时都使用join吧

多进程之自定义创建进程方式

import multiprocessing as mp
def foo(q):
    q.put('hello')

if __name__ == '__main__':
    ctx = mp.get_context('spawn')  # 通过获取上下文方式设置创建进程方式
    q = ctx.Queue()
    p = ctx.Process(target=foo, args=(q,))
    p.start()
    print(q.get())
    p.join()

# 多进程支持多种创建方式spawn,fork, forkserver
# spawn 支持unix和windows,这个方式在windows是默认的创建方式,这个方法效率低于fork和forkserver
# fork 仅支持unix,unix平台默认创建方式为fork,
# forkserver 支持能在unix平台传递文件描述符的管道平台

# 不同的创建进程方式之间是不兼容的,特别是锁创建,使用fork上下文,是不能启动使用spawn或forkserver方式创建的进程

多进程之Queue队列实现进程间数据共享

from multiprocessing import Pool, Process, Queue
def f(q):
    q.put([42, None, 'hello'])  # 子进程放入的数据,


if __name__ == '__main__':
    q = Queue()
    p = Process(target=f, args=(q,))
    p.start()
    print(q.get())  # 父进程获取子进程的数据
    p.join()
# 进程间的数据是不共享的,如果需要交换数据,需要使用进程模块的Queue队列方法
# 队列是线程和进程安全的

多进程之Pipe管道实现进程间数据通信

from multiprocessing import Pool, Process, Queue, Pipe
def f(conn):
    conn.send([42, None, 'hello'])  # 子进程通过管道向管道发生数据
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()  # 获取一对管道
    p = Process(target=f, args=(child_conn,))  # 将其中一个管道传给子进程
    p.start()
    print(parent_conn.recv())  # 使用另一个管道接受数据
    p.join()

# 通过管道也能实现进程间数据通信

多进程之Lock实现数据同步

from multiprocessing import Pool, Process, Queue, Pipe, Lock
def f(l, i):
    l.acquire()  # 加锁后,其他进程将被阻塞,只有最先调用acquire获得锁的进程才能执行
    try:
        print('hello world', i)
    finally:
        l.release()  # 调用release释放锁后,其他进程将又会抢占资源


if __name__ == '__main__':
    lock = Lock()
    for num in range(10):
        Process(target=f, args=(lock, num)).start()  # 由于进程创建后就立即执行,所以该例子最终变成串行方式

# 通过加锁使进程间对于同一个资源的使用保持同步,避免脏数据,加锁后,得到锁的进程会锁定资源,其他进程将进入阻塞状态,直到锁被释放,所有进程又将开始抢占资源,直到某一个进程又获得了锁,这时其他没有获得锁的进程又被阻塞

多进程之进程间数据状态共享

from multiprocessing import Pool, Process, Queue, Pipe, Lock, Value, Array
def f(n, a):
    n.value = 3.1415927
    for i in range(len(a)):  # 子进程对父进程传进来的数据进行修改
        a[i] = -a[i]


if __name__ == '__main__':
    num = Value('d', 0.0)  # 第一个参数为数据类型,d为double双精度浮点型,适合单个值状态共享
    arr = Array('i', range(10))  # 第一个参数是数据的类型,i为整型,适合多个值状态共享

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

    print(num.value)
    print(arr[:])  # 父进程访问子访问子进程操作过的数据,这个数据通常讲,进程间的数据是独立的,但是通过这种方式,实现了进程间的数据也能实现状态共享,这里的数组使用[:]分片表示将数据拷贝了一份

# 上面进程间同步时需要我们手动加锁,避免进程对同一个资源同时修改,我们也可以使用Value或Array两个方法,实现进程间的数据状态共享,其内部也是通过加锁方式避免了脏数据产生

多进程之Manager代理,实现进程间数据共享

from multiprocessing import Pool, Process, Queue, Pipe, Lock, Value, Array, Manager
def f(d, l):
    d[1] = '1'
    d['2'] = 2
    d['0.25'] = None
    l.reverse()


if __name__ == '__main__':
    with Manager() as manager:
        d = manager.dict()  # 由manager代理的python 字典对象
        l = manager.list(range(10))  # 由manager代理的python列表对象

        p = Process(target=f, args=(d, l))  # 由子进程进行操作代理的数据
        p.start()
        p.join()

        print(d)  # 父进程访问数据时与子进程数据保持同步
        print(l)

# 通过Manager来代理进程间操作python对象,这样也能实现进程间数据共享。
#Manager支持代理的对象list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value 
原文地址:https://www.cnblogs.com/zengchunyun/p/7127538.html