python 多进程数据交互及共享

多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。

不同进程之间内存是不共享的,要实现两个进程间的数据交换,可以用以下方法:

queues

使用方法和threading里面的queue差不多

from multiprocessing import Process,Queue

def f(q):
    q.put([2,None,'hello'])

if __name__ =='__main__':
    q = Queue()
    p = Process(target=f,args=(q,))
    p.start()
    print(q.get())
    p.join()

 运行结果

[2, None, 'hello']

多进程中,对于一个变量,每个进程都是复制了一份,所以每个进程之间修改数据互不影响。 Queue()方法相当于第三方,把进程A的数据序列化后传给进程B 反序列化得到数据。并不是一个共享的变量。而是实现了数据的传递。

Pipes 管道

类似于socket 一端发送,一端接收,实现通信。

from multiprocessing import Process,Pipe

def f(conn):
    conn.send([5,'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()

 运行结果

[5, 'hello']

 发送方和接收方的关系,也和socket类似,发送方发送几次,接收方就要接收几次。接收方如果接收的次数多于发送方,那么接收方就会卡住,直到发送方在发送一次。

相互通信

def f(conn):
    conn.send([5,'hello'])   #发送数据
    print(conn.recv())         #接收数据
    conn.close()


if __name__ =='__main__':
    parent_conn,child_conn = Pipe()
    p = Process(target=f,args=(child_conn,))
    p.start()
    print(parent_conn.recv())         #接收数据
    parent_conn.send("hehe你好")  #发送数据
    p.join()

 Managers

由manager()返回的manager对象控制一个包含Python对象的服务器进程,并允许其他进程使用代理来操作它们。

由manager()返回的管理器将支持类型列表、命令、名称空间、锁、RLock、信号量、BoundedSemaphore、Condition、Event、Barrier、Queue、Value和Array。

from multiprocessing import Process, Manager


def f(d, l):
    d[1] = '1'
    d['2'] = 2
    d[0.25] = None
    l.append(1)
    print(l)


if __name__ == '__main__':
    with Manager() as manager:
        d = manager.dict()  #生成一个字典,可以在多个进程中传递和共享。

        l = manager.list(range(5)) #生成一个列表,在多个进程中传递和共享。
        p_list = []    #存放进程对象
        for i in range(10):
            p = Process(target=f, args=(d, l))
            p.start()
            p_list.append(p)
        for res in p_list:
            res.join()  #等待进程结束

        print(d)
        print(l)

 运行结果

[0, 1, 2, 3, 4, 1]
[0, 1, 2, 3, 4, 1, 1]
[0, 1, 2, 3, 4, 1, 1, 1]
[0, 1, 2, 3, 4, 1, 1, 1, 1]
[0, 1, 2, 3, 4, 1, 1, 1, 1, 1]
[0, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1]
[0, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1]
[0, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1]
[0, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[0, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
{0.25: None, 1: '1', '2': 2}
[0, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

 以上实现了进程之间的数据共享,不是数据传递,而是真正的共享。并且可以同时修改。

Manager()内部有加锁机制,不允许两个进程同时修改一份数据,因为进程的数据是独立的。

原文地址:https://www.cnblogs.com/qing-chen/p/7688343.html