成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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類開始講解。

開始學(xué)習(xí)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() 

 

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

當(dāng)你運行上面的代碼,你應(yīng)該看到和下面類似的輸出結(jié)果:

  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() 

 

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

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

  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 

 

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

multiprocessing模塊支持鎖,它和threading模塊做的方式一樣。你需要做的只是導(dǎo)入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包不使用共享鎖的進程,因此有可能以來自不同進程的信息作為結(jié)束的標(biāo)志。讓我們試著給前面的例子添加基本的日志。代碼如下:

  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實例,并將它的日志等級設(shè)為INFO。之后的代碼是相同的。需要提示下這里我并沒有調(diào)用join()方法。取而代之的:當(dāng)它退出,父線程將自動調(diào)用join()方法。

當(dāng)你這么做了,你應(yīng)該得到類似下面的輸出:

  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閱讀一些有關(guān)那類話題。

Pool類

Pool類被用來代表一個工作進程池。它有讓你將任務(wù)轉(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ù)和一個可迭代對象映射到每個進程。***我們打印出這個例子的結(jié)果:[10, 20, 40]。

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

  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)) 

 

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

進程通信

當(dāng)遇到進程間通信的情況,multiprocessing 模塊提供了兩個主要的方法:Queues 和 Pipes。Queue 實現(xiàn)上既是線程安全的也是進程安全的。讓我們看一個相當(dāng)簡單的并且基于 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() 

 

在這里我們只需要導(dǎo)入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)用。

總結(jié)

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

相關(guān)閱讀

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

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ā)框架

2016-01-11 10:29:36

Docker容器容器技術(shù)

2021-10-12 09:52:30

Webpack 前端多進程打包

2021-06-11 06:54:35

PythonThreadingMultiproces

2023-12-11 18:18:24

Python編程線程

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

2019-03-12 09:20:09

shell爬蟲命名

2010-07-15 13:13:21

Perl多進程

2022-04-19 20:39:03

協(xié)程多進程

2021-06-16 07:21:39

AndroidAndroid系統(tǒng)多進程通訊

2010-07-14 11:27:42

Perl多進程
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 丁香久久| 日韩毛片| 久久久亚洲综合 | 一级视频在线免费观看 | 国产成人综合网 | 日干夜干 | 亚洲精品自在在线观看 | 91精品国产综合久久久久久丝袜 | 成年人在线视频 | 91久久精品一区 | 亚洲第一成年免费网站 | 亚洲成年影院 | 久久成人18免费网站 | 欧美高清视频一区 | 男人天堂网av | 理论片免费在线观看 | 51ⅴ精品国产91久久久久久 | 免费久久久久久 | 欧美日韩视频在线播放 | 精品乱子伦一区二区三区 | 啪视频在线 | 久久成人免费视频 | 毛片视频网址 | 中文字幕成人 | 欧美福利精品 | 91高清免费 | 久久99久久99精品免视看婷婷 | 欧美国产日韩精品 | 久久久久久av | 91久久精品一区二区二区 | 国产在线高清 | 亚洲区一区二区 | 亚洲乱码一区二区三区在线观看 | 国产在线看片 | 久久成人激情 | 久久91精品久久久久久9鸭 | 91麻豆精品国产91久久久更新资源速度超快 | 日韩三级电影在线看 | 欧美日韩在线免费观看 | 高清久久久 | 欧美电影免费观看 |