自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Python多進程教程

開發(fā) 后端
Python2.6版本中新添了multiprocessing模塊。它最初由Jesse Noller和Richard Oudkerk定義在PEP 371中。就像你能通過threading模塊衍生線程一樣,multiprocessing 模塊允許你衍生進程。這里用到的思想:因為你現(xiàn)在能衍生進程,所以你能夠避免使用全局解釋器鎖(GIL),并且充分利用機器的多個處理器。

Python多進程教程

Python2.6版本中新添了multiprocessing模塊。它最初由Jesse Noller和Richard Oudkerk定義在PEP 371中。就像你能通過threading模塊衍生線程一樣,multiprocessing 模塊允許你衍生進程。這里用到的思想:因為你現(xiàn)在能衍生進程,所以你能夠避免使用全局解釋器鎖(GIL),并且充分利用機器的多個處理器。

多進程包也包含一些根本不在threading 模塊中的API。比如:有一個靈活的Pool類能讓你在多個輸入下并行化地執(zhí)行函數(shù)。我們將在后面的小節(jié)講解Pool類。我們將以multiprocessing模塊的Process類開始講解。

開始學習multiprocessing模塊

Process這個類和threading模塊中的Thread類很像。讓我們創(chuàng)建一系列調(diào)用相同函數(shù)的進程,并且看看它是如何工作的。

  1. import os 
  2.  
  3. from multiprocessing import Process 
  4.  
  5. def doubler(number): 
  6.  
  7.     ""
  8.  
  9.     A doubling function that can be used by a process 
  10.  
  11.     ""
  12.  
  13.     result = number * 2 
  14.  
  15.     proc = os.getpid() 
  16.  
  17.     print('{0} doubled to {1} by process id: {2}'.format( 
  18.  
  19.         number, result, proc)) 
  20.  
  21. if __name__ == '__main__'
  22.  
  23.     numbers = [5, 10, 15, 20, 25] 
  24.  
  25.     procs = [] 
  26.  
  27.     for index, number in enumerate(numbers): 
  28.  
  29.         proc = Process(target=doubler, args=(number,)) 
  30.  
  31.         procs.append(proc) 
  32.  
  33.         proc.start() 
  34.  
  35.     for proc in procs: 
  36.  
  37.         proc.join() 

 

對于上面的例子,我們導入Process類、創(chuàng)建一個叫doubler的函數(shù)。在函數(shù)中,我們將傳入的數(shù)字乘上2。我們也用Python的os模塊來獲取當前進程的ID(pid)。這個ID將告訴我們哪個進程正在調(diào)用doubler函數(shù)。然后,在下面的代碼塊中,我們實例化了一系列的Process類并且啟動它們。***一個循環(huán)只是調(diào)用每個進程的join()方法,該方法告訴Python等待進程直到它結束。如果你需要結束一個進程,你可以調(diào)用它的terminate()方法。

當你運行上面的代碼,你應該看到和下面類似的輸出結果:

  1. 5 doubled to 10 by process id: 10468 
  2.  
  3. 10 doubled to 20 by process id: 10469 
  4.  
  5. 15 doubled to 30 by process id: 10470 
  6.  
  7. 20 doubled to 40 by process id: 10471 
  8.  
  9. 25 doubled to 50 by process id: 10472 

 

有時候,你***給你的進程取一個易于理解的名字 。幸運的是,Process類確實允許你訪問同樣的進程。讓我們來看看如下例子:

  1. import os 
  2.  
  3. from multiprocessing import Process, current_process 
  4.  
  5. def doubler(number): 
  6.  
  7.     ""
  8.  
  9.     A doubling function that can be used by a process 
  10.  
  11.     ""
  12.  
  13.     result = number * 2 
  14.  
  15.     proc_name = current_process().name 
  16.  
  17.     print('{0} doubled to {1} by: {2}'.format( 
  18.  
  19.         number, result, proc_name)) 
  20.  
  21. if __name__ == '__main__'
  22.  
  23.     numbers = [5, 10, 15, 20, 25] 
  24.  
  25.     procs = [] 
  26.  
  27.     proc = Process(target=doubler, args=(5,)) 
  28.  
  29.     for index, number in enumerate(numbers): 
  30.  
  31.         proc = Process(target=doubler, args=(number,)) 
  32.  
  33.         procs.append(proc) 
  34.  
  35.         proc.start() 
  36.  
  37.     proc = Process(target=doubler, name='Test', args=(2,)) 
  38.  
  39.     proc.start() 
  40.  
  41.     procs.append(proc) 
  42.  
  43.     for proc in procs: 
  44.  
  45.         proc.join() 

 

這一次,我們多導入了current_process。current_process基本上和threading模塊的current_thread是類似的東西。我們用它來獲取正在調(diào)用我們的函數(shù)的線程的名字。你將注意到我們沒有給前面的5個進程設置名字。然后我們將第6個進程的名字設置為“Test”。

讓我們看看我們將得到什么樣的輸出結果:

  1. 5 doubled to 10 by: Process-2 
  2.  
  3. 10 doubled to 20 by: Process-3 
  4.  
  5. 15 doubled to 30 by: Process-4 
  6.  
  7. 20 doubled to 40 by: Process-5 
  8.  
  9. 25 doubled to 50 by: Process-6 
  10.  
  11. 2 doubled to 4 by: Test 

 

輸出結果說明:默認情況下,multiprocessing模塊給每個進程分配了一個編號,而該編號被用來組成進程的名字的一部分。當然,如果我們給定了名字的話,并不會有編號被添加到名字中。

multiprocessing模塊支持鎖,它和threading模塊做的方式一樣。你需要做的只是導入Lock,獲取它,做一些事,釋放它。

  1. from multiprocessing import Process, Lock 
  2.  
  3. def printer(item, lock): 
  4.  
  5.     ""
  6.  
  7.     Prints out the item that was passed in 
  8.  
  9.     ""
  10.  
  11.     lock.acquire() 
  12.  
  13.     try: 
  14.  
  15.         print(item) 
  16.  
  17.     finally: 
  18.  
  19.         lock.release() 
  20.  
  21. if __name__ == '__main__'
  22.  
  23.     lock = Lock() 
  24.  
  25.     items = ['tango''foxtrot', 10] 
  26.  
  27.     for item in items: 
  28.  
  29.         p = Process(target=printer, args=(item, lock)) 
  30.  
  31.         p.start() 

 

我們在這里創(chuàng)建了一個簡單的用于打印函數(shù),你輸入什么,它就輸出什么。為了避免線程之間互相阻塞,我們使用Lock對象。代碼循環(huán)列表中的三個項并為它們各自都創(chuàng)建一個進程。每一個進程都將調(diào)用我們的函數(shù),并且每次遍歷到的那一項作為參數(shù)傳入函數(shù)。因為我們現(xiàn)在使用了鎖,所以隊列中下一個進程將一直阻塞,直到之前的進程釋放鎖。

日志

為進程創(chuàng)建日志與為線程創(chuàng)建日志有一些不同。它們存在不同是因為Python的logging包不使用共享鎖的進程,因此有可能以來自不同進程的信息作為結束的標志。讓我們試著給前面的例子添加基本的日志。代碼如下:

  1. import logging 
  2.  
  3. import multiprocessing 
  4.  
  5. from multiprocessing import Process, Lock 
  6.  
  7. def printer(item, lock): 
  8.  
  9.     ""
  10.  
  11.     Prints out the item that was passed in 
  12.  
  13.     ""
  14.  
  15.     lock.acquire() 
  16.  
  17.     try: 
  18.  
  19.         print(item) 
  20.  
  21.     finally: 
  22.  
  23.         lock.release() 
  24.  
  25. if __name__ == '__main__'
  26.  
  27.     lock = Lock() 
  28.  
  29.     items = ['tango''foxtrot', 10] 
  30.  
  31.     multiprocessing.log_to_stderr() 
  32.  
  33.     logger = multiprocessing.get_logger() 
  34.  
  35.     logger.setLevel(logging.INFO) 
  36.  
  37.     for item in items: 
  38.  
  39.         p = Process(target=printer, args=(item, lock)) 
  40.  
  41.         p.start() 

 

最簡單的添加日志的方法通過推送它到stderr實現(xiàn)。我們能通過調(diào)用thelog_to_stderr() 函數(shù)來實現(xiàn)該方法。然后我們調(diào)用get_logger 函數(shù)獲得一個logger實例,并將它的日志等級設為INFO。之后的代碼是相同的。需要提示下這里我并沒有調(diào)用join()方法。取而代之的:當它退出,父線程將自動調(diào)用join()方法。

當你這么做了,你應該得到類似下面的輸出:

  1. [INFO/Process-1] child process calling self.run() 
  2.  
  3. tango 
  4.  
  5. [INFO/Process-1] process shutting down 
  6.  
  7. [INFO/Process-1] process exiting with exitcode 0 
  8.  
  9. [INFO/Process-2] child process calling self.run() 
  10.  
  11. [INFO/MainProcess] process shutting down 
  12.  
  13. foxtrot 
  14.  
  15. [INFO/Process-2] process shutting down 
  16.  
  17. [INFO/Process-3] child process calling self.run() 
  18.  
  19. [INFO/Process-2] process exiting with exitcode 0 
  20.  
  21. 10 
  22.  
  23. [INFO/MainProcess] calling join() for process Process-3 
  24.  
  25. [INFO/Process-3] process shutting down 
  26.  
  27. [INFO/Process-3] process exiting with exitcode 0 
  28.  
  29. [INFO/MainProcess] calling join() for process Process-2 

 

現(xiàn)在如果你想要保存日志到硬盤中,那么這件事就顯得有些棘手。你能在Python的logging Cookbook閱讀一些有關那類話題。

Pool類

Pool類被用來代表一個工作進程池。它有讓你將任務轉(zhuǎn)移到工作進程的方法。讓我們看下面一個非常簡單的例子。

  1. from multiprocessing import Pool 
  2.  
  3. def doubler(number): 
  4.  
  5.     return number * 2 
  6.  
  7. if __name__ == '__main__'
  8.  
  9.     numbers = [5, 10, 20] 
  10.  
  11.     pool = Pool(processes=3) 
  12.  
  13.     print(pool.map(doubler, numbers)) 

 

基本上執(zhí)行上述代碼之后,一個Pool的實例被創(chuàng)建,并且該實例創(chuàng)建了3個工作進程。然后我們使用map 方法將一個函數(shù)和一個可迭代對象映射到每個進程。***我們打印出這個例子的結果:[10, 20, 40]。

你也能通過apply_async方法獲得池中進程的運行結果:

  1. from multiprocessing import Pool 
  2.  
  3. def doubler(number): 
  4.  
  5.     return number * 2 
  6.  
  7. if __name__ == '__main__'
  8.  
  9.     pool = Pool(processes=3) 
  10.  
  11.     result = pool.apply_async(doubler, (25,)) 
  12.  
  13.     print(result.get(timeout=1)) 

 

我們上面做的事實際上就是請求進程的運行結果。那就是get函數(shù)的用途。它嘗試去獲取我們的結果。你能夠注意到我們設置了timeout,這是為了預防我們調(diào)用的函數(shù)發(fā)生異常的情況。畢竟我們不想要它被***期地阻塞。

進程通信

當遇到進程間通信的情況,multiprocessing 模塊提供了兩個主要的方法:Queues 和 Pipes。Queue 實現(xiàn)上既是線程安全的也是進程安全的。讓我們看一個相當簡單的并且基于 Queue的例子。代碼來自于我的文章(threading articles)。

  1. from multiprocessing import Process, Queue 
  2.  
  3. sentinel = -1 
  4.  
  5. def creator(data, q): 
  6.  
  7.     ""
  8.  
  9.     Creates data to be consumed and waits for the consumer 
  10.  
  11.     to finish processing 
  12.  
  13.     ""
  14.  
  15.     print('Creating data and putting it on the queue'
  16.  
  17.     for item in data: 
  18.  
  19.         q.put(item) 
  20.  
  21. def my_consumer(q): 
  22.  
  23.     ""
  24.  
  25.     Consumes some data and works on it 
  26.  
  27.     In this caseall it does is double the input 
  28.  
  29.     ""
  30.  
  31.     while True
  32.  
  33.         data = q.get() 
  34.  
  35.         print('data found to be processed: {}'.format(data)) 
  36.  
  37.         processed = data * 2 
  38.  
  39.         print(processed) 
  40.  
  41.         if data is sentinel: 
  42.  
  43.             break 
  44.  
  45. if __name__ == '__main__'
  46.  
  47.     q = Queue() 
  48.  
  49.     data = [5, 10, 13, -1] 
  50.  
  51.     process_one = Process(target=creator, args=(data, q)) 
  52.  
  53.     process_two = Process(target=my_consumer, args=(q,)) 
  54.  
  55.     process_one.start() 
  56.  
  57.     process_two.start() 
  58.  
  59.     q.close() 
  60.  
  61.     q.join_thread() 
  62.  
  63.     process_one.join() 
  64.  
  65.     process_two.join() 

 

在這里我們只需要導入Queue和Process。Queue用來創(chuàng)建數(shù)據(jù)和添加數(shù)據(jù)到隊列中,Process用來消耗數(shù)據(jù)并執(zhí)行它。通過使用Queue的put()和get()方法,我們就能添加數(shù)據(jù)到Queue、從Queue獲取數(shù)據(jù)。代碼的***一塊只是創(chuàng)建了Queue 對象以及兩個Process對象,并且運行它們。你能注意到我們在進程對象上調(diào)用join()方法,而不是在Queue本身上調(diào)用。

總結

我們這里有大量的資料。你已經(jīng)學習如何使用multiprocessing模塊指定不變的函數(shù)、使用Queues在進程間通信、給進程命名等很多事。在Python文檔中也有很多本文沒有接觸到的知識點,因此也務必深入了解下文檔。與此同時,你現(xiàn)在知道如何用Python利用你電腦所有的處理能力了!

相關閱讀

  • 有關multiprocessing模塊的Python文檔(multiprocessing module)
  • Python模塊周刊:multiprocessing
  • Python的并發(fā)–Porting a Queue to multiprocessing 
責任編輯:龐桂玉 來源: Python開發(fā)者
相關推薦

2024-03-29 06:44:55

Python多進程模塊工具

2022-03-09 17:01:32

Python多線程多進程

2020-11-18 09:06:04

Python

2010-07-15 12:51:17

Perl多進程

2020-04-07 11:10:30

Python數(shù)據(jù)線程

2012-08-08 09:32:26

C++多進程并發(fā)框架

2021-10-12 09:52:30

Webpack 前端多進程打包

2016-01-11 10:29:36

Docker容器容器技術

2023-12-11 18:18:24

Python編程線程

2021-06-11 06:54:35

PythonThreadingMultiproces

2024-08-26 08:39:26

PHP孤兒進程僵尸進程

2019-02-26 11:15:25

進程多線程多進程

2009-04-21 09:12:45

Java多進程運行

2021-02-25 11:19:37

谷歌Android開發(fā)者

2022-07-11 10:23:42

云原生Python多核CPU

2017-04-25 15:20:11

Python進程mpi4py

2020-11-17 10:50:37

Python

2010-07-14 11:27:42

Perl多進程

2023-12-13 09:56:13

?多進程多線程協(xié)程

2019-03-12 09:20:09

shell爬蟲命名
點贊
收藏

51CTO技術棧公眾號