python 3.x 进程间通信

进程间通信

  • 进程间通信与线程间通信有共同点和不同点.
    • 不同点:是在多线程用到的线程间通信的类和线程间同步的锁在多进程中是不能用的
  • 进程间的通信方法:
    • 1.需要使用multiprocessing包下的Manager  
        def Manager():
                     return multiprocessing.SyncManager()
             queue = Manager().Queue(10) 通过Manager().Queue(10)来创建队列,可以被Pool创建进程间通信进程池使用
             Pool进程池中的进程间通信需要使用Manager中的queue    
    • 2.进程间通信第二种方式:管道Pipe(简化版的一个Queue)  
      • Pipe()返回两个Connection对象,第一个是接收Pipe,第二个是发送Pipe    
      • Pipe只能适用于两个指定的进程,进行进程间的通信.    
      • pipe的性能高于queue,queue用来进程或者线程间的同步,所以queue加了很多的锁.所以说queue做同步的话,降低queue的性能 
      •  1         def Pipe(duplex=True):
         2             return Connection(), Connection()
         3 
         4         class Connection(object):
         5             # 发送数据
         6             def send(self, obj):
         7             # 接收数据
         8             def recv(self):
         9             def fileno(self):
        10                 return 0
        11             def close(self):
        12             def poll(self, timeout=None):
        13             def send_bytes(self, buffer, offset=-1, size=-1):
        14             def recv_bytes(self, maxlength=-1):
        15             def recv_bytes_into(self, buffer, offset=-1):
        16             def __enter__(self):
        17             def __exit__(self, exc_type, exc_val, exc_tb):
    • 3.进程间通信的其他方式:  
      • 虽然说进程间的变量是单独隔离的,但是在某些情况之下,我们还是希望,我们能够像线程一样在进程间维护一个公共的内存模块,或者说公共的变量.multiprocessing可以帮我们做到from multiprocessing import Manager.
      • 进程间是共享内存操作
      •  1 # 调用Manager()返回SyncManager对象.
         2         def Manager():
         3             return multiprocessing.SyncManager()
         4 
         5         # 进程间同步的操作方法:(使用方法与线程间的同步是一样的)
         6         class SyncManager(multiprocessing.managers.BaseManager):
         7             def Barrier(self, parties, action=None, timeout=None):
         8                 return threading.Barrier(parties, action, timeout)
         9 
        10             def BoundedSemaphore(self, value=None):
        11                 return threading.BoundedSemaphore(value)
        12 
        13             def Condition(self, lock=None):
        14                 return threading.Condition(lock)
        15 
        16             def Event(self):
        17                 return threading.Event()
        18 
        19             def Lock(self):
        20                 return threading.Lock()
        21 
        22             def Namespace(self):
        23                 pass
        24 
        25             def Queue(self, maxsize=None):
        26                 return queue.Queue()
        27 
        28             def RLock(self):
        29                 return threading.RLock()
        30 
        31             def Semaphore(self, value=None):
        32                 return threading.Semaphore(value)
        33 
        34             def Array(self, typecode, sequence):
        35                 pass
        36 
        37             def Value(self, typecode, value):
        38                 pass
        39 
        40             def dict(self, mapping_or_sequence):
        41                 pass
        42 
        43             def list(self, sequence):
        44                 pass
        45 
        46         # 使用Manager里面的数据结构,来完成进程间的一个内存共享,在使用内存共享的时候,一定要注意数据的同步

         

 

  • 假设使用多线程的queue来实现多进程间的通信,看看什么效果???
    • 报错:TypeError: can't pickle _thread.lock objects
    • 多线程的queue应用到多进程会抛异常的
 1 """
 2 假设使用多线程的queue来实现多进程间的通信,看看什么效果???
 3 """
 4 
 5 from multiprocessing import Process
 6 import time
 7 from queue import Queue
 8 
 9 
10 def producer(queue):
11     queue.put("a")
12     time.sleep(2)
13 
14 
15 def consumer(queue):
16     # 等待producer添加数据
17     time.sleep(2)
18     data = queue.get()
19     print(data)
20 
21 
22 if __name__ == '__main__':
23     queue = Queue(10)
24     my_producer = Process(target=producer, args=(queue,))
25     my_consumer = Process(target=consumer, args=(queue,))
26 
27     my_producer.start()
28     my_consumer.start()
29 
30     my_producer.join()
31     my_consumer.join()
32 """
33 报错:TypeError: can't pickle _thread.lock objects
34 """

 

 

使用multiprocessing包下的Queue来实现多进程间的通信

 1 """
 2 使用multiprocessing包下的Queue来实现多进程间的通信
 3 """
 4 
 5 from multiprocessing import Process, Queue
 6 import time
 7 
 8 
 9 def producer(queue):
10     queue.put("a")
11     time.sleep(2)
12 
13 
14 def consumer(queue):
15     # 等待producer添加数据
16     time.sleep(2)
17     data = queue.get()
18     print(data)
19 
20 
21 if __name__ == '__main__':
22     queue = Queue(10)
23     my_producer = Process(target=producer, args=(queue,))
24     my_consumer = Process(target=consumer, args=(queue,))
25 
26     my_producer.start()
27     my_consumer.start()
28 
29     my_producer.join()
30     my_consumer.join()
31 """
32 输出结果:a
33 """

 

在说明多进程编程之前举一个小案例fork(在linux系统下运行)演示进程间的关系(小案例链接)

  • 因为多进程的数据完全是隔离的,当fork一个数据的时候,fork会将进程里面的所有全局变量完全复制一份,复制到子进程中,然后两边的数据做修改的时候,是不会互相影响的.  
  • 所以下面代码的共享全局变量不管在另一个进程中怎么修改,都不会影响另一个进程中共享全局变量的值.  
  • 因为进程间的数据是相互独立的  
 1 """
 2 使用共享全局变量来实现多进程间的通信
 3     通过输出结果,说明全局共享变量是不适用多进程编程.
 4     可以适用多线程编程,前提需要对共享全局变量做同步(加锁).
 5 """
 6 
 7 from multiprocessing import Process
 8 import time
 9 
10 
11 def producer(a):
12     a += 100
13     time.sleep(2)
14 
15 
16 def consumer(a):
17     # 等待producer添加数据
18     time.sleep(2)
19     print("a = {}".format(a))
20 
21 
22 if __name__ == '__main__':
23     a = 1
24     my_producer = Process(target=producer, args=(a,))
25     my_consumer = Process(target=consumer, args=(a,))
26 
27     my_producer.start()
28     my_consumer.start()
29 
30     my_producer.join()
31     my_consumer.join()
32 """
33 输出结果:
34     a = 1,不管加多少,输出结果都是a = 1.
35 """

 

 

使用multiprocessing包下的Queue来实现多进程间的通信,但是Queue不能用在multiprocessing.Pool线程池中

 1 """
 2 使用multiprocessing包下的Queue来实现多进程间的通信,但是Queue不能用在multiprocessing.Pool线程池中
 3 """
 4 
 5 from multiprocessing import Queue, Pool
 6 import time
 7 
 8 
 9 def producer(queue):
10     queue.put("a")
11     time.sleep(2)
12 
13 
14 def consumer(queue):
15     # 等待producer添加数据
16     time.sleep(2)
17     data = queue.get()
18     print(data)
19 
20 
21 if __name__ == '__main__':
22     queue = Queue(10)
23     pool = Pool(2)
24     pool.apply_async(producer, args=(queue,))
25     pool.apply_async(consumer, args=(queue,))
26 
27     pool.close()
28 
29     pool.join()
30 
31 """
32 输出结果:没有任何结果输出.
33 
34     按照我们的理解,如果multiprocessing中的Queue可以用在Pool创建进程间通信进程池,是应该有输出结果.
35     但是实际运行没有任何结果,所以说multiprocessing中的Queue是不能直接用于进程池里面的进程间通信的.
36 """

 

 

 1 """
 2 如何使进程池中的进程之间可以互相通信呢???
 3     1.需要使用multiprocessing包下的Manager
 4         def Manager():
 5             return multiprocessing.SyncManager()
 6         queue = Manager().Queue(10) 通过Manager().Queue(10)来创建队列,可以被Pool创建进程间通信进程池使用
 7         Pool进程池中的进程间通信需要使用Manager中的queue
 8 """
 9 
10 from multiprocessing import Pool, Manager
11 import time
12 
13 
14 def producer(queue):
15     queue.put("a")
16     time.sleep(2)
17 
18 
19 def consumer(queue):
20     # 等待producer添加数据
21     time.sleep(2)
22     data = queue.get()
23     print(data)
24 
25 
26 if __name__ == '__main__':
27     # 通过Manager().Queue(10)来创建队列,可以被Pool创建进程间通信进程池使用
28     queue = Manager().Queue(10)
29     pool = Pool(2)
30     pool.apply_async(producer, args=(queue,))
31     pool.apply_async(consumer, args=(queue,))
32 
33     pool.close()
34 
35     pool.join()
36 
37 """
38 输出结果: a
39 """

 

 

 1 """
 2 2.进程间通信第二种方式:管道Pipe(简化版的一个Queue)
 3    Pipe()返回两个Connection对象,第一个是接收Pipe,第二个是发送Pipe
 4    Pipe只能适用于两个指定的进程,进行进程间的通信.
 5 
 6    pipe的性能高于queue,queue用来进程或者线程间的同步,所以queue加了很多的锁.所以说queue做同步的话,降低queue的性能
 7 """
 8 
 9 from multiprocessing import Pipe, Process
10 
11 
12 def producer(pipe):
13     pipe.send("jayden")
14 
15 
16 def consumer(pipe):
17     print(pipe.recv())
18 
19 
20 if __name__ == '__main__':
21     # Pipe()返回两个Connection对象,第一个是接收Pipe,第二个是发送Pipe
22     receiver_pipe, send_pipe = Pipe()
23 
24     my_producer = Process(target=producer, args=(send_pipe,))
25     my_consumer = Process(target=consumer, args=(receiver_pipe,))
26 
27     my_producer.start()
28     my_consumer.start()
29 
30     my_producer.join()
31     my_consumer.join()
32 
33 """
34 输出结果: jayden
35 """

 

 

 1 """
 2 3.进程间通信的其他方式:
 3     虽然说进程间的变量是单独隔离的,但是在某些情况之下,我们还是希望,我们能够像线程一样在进程间维护一个公共的内存模块,
 4     或者说公共的变量.multiprocessing可以帮我们做到from multiprocessing import Manager
 5 
 6     进程间是共享内存操作
 7 
 8     # 调用Manager()返回SyncManager对象.
 9     def Manager():
10         return multiprocessing.SyncManager()
11 
12     # 进程间同步的操作方法:(使用方法与线程间的同步是一样的)
13         class SyncManager(multiprocessing.managers.BaseManager):
14             ...
15 
16             def dict(self, mapping_or_sequence):
17                 pass
18             ...
19         
20     # 使用Manager里面的数据结构,来完成进程间的一个内存共享,在使用内存共享的时候,一定要注意数据的同步
21 
22 """
23 
24 from multiprocessing import Manager, Process
25 
26 
27 def add_data(pg_dict, key, value):
28     pg_dict[key] = value
29 
30 
31 if __name__ == '__main__':
32     progress_dict = Manager().dict()
33 
34     first_process = Process(target=add_data, args=(progress_dict, "jayden", 18))
35     second_process = Process(target=add_data, args=(progress_dict, "python", 5))
36 
37     first_process.start()
38     second_process.start()
39 
40     first_process.join()
41     second_process.join()
42 
43     print(progress_dict)
44 
45 """
46 输出结果: {'jayden': 18, 'python': 5}
47 """

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

********

posted on 2019-05-06 09:59  jaydenjune  阅读(51)  评论(0)    收藏  举报

导航