簡體   English   中英

Python Jupyter Notebook 內的多處理

[英]Python Multiprocessing within Jupyter Notebook

我是 Python 中的multiprocessing模塊的新手,並且可以使用 Jupyter 筆記本。 我嘗試了PMOTW的以下代碼片段:

import multiprocessing

def worker():
    """worker function"""
    print('Worker')
    return

if __name__ == '__main__':
    jobs = []
    for i in range(5):
        p = multiprocessing.Process(target=worker)
        jobs.append(p)
        p.start()

當我按原樣運行時,沒有 output。

我還嘗試創建一個名為worker.py的模塊,然后將其導入以運行代碼:

import multiprocessing
from worker import worker

if __name__ == '__main__':
    jobs = []
    for i in range(5):
        p = multiprocessing.Process(target=worker)
        jobs.append(p)
        p.start()

在這種情況下仍然沒有 output。 在控制台中,我看到以下錯誤(重復多次):

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Program Files\Anaconda3\lib\multiprocessing\spawn.py", line 106, in spawn_main
    exitcode = _main(fd)
  File "C:\Program Files\Anaconda3\lib\multiprocessing\spawn.py", line 116, in _main
    self = pickle.load(from_parent)
AttributeError: Can't get attribute 'worker' on <module '__main__' (built-in)>

但是,當代碼保存為 Python 腳本並執行時,我得到了預期的 output。

我可以做些什么來直接從筆記本運行此代碼而不創建單獨的腳本?

我對並行計算比較陌生,所以我可能對一些技術有誤。 我的理解是這樣的:

Jupyter 筆記本不適用於multiprocessing ,因為模塊會腌制(序列化)數據以發送到進程。 multiprocessmultiprocessing的一個分支,它使用 dill 而不是 pickle 來序列化數據,這允許它在 Jupyter notebook 中工作。 API 是相同的,因此您唯一需要做的就是更改

import multiprocessing

至...

import multiprocess

你可以很容易地安裝multiprocess

pip install multiprocess

但是,您會發現您的進程仍然不會打印到輸出(盡管在 Jupyter 實驗室中,它們會打印到服務器輸出正在運行的終端)。 我偶然發現這篇文章試圖解決這個問題,當我知道如何做時會編輯這篇文章。

我不是multiprocessingipykernel (由 jupyter notebook 使用)中的導出,但因為似乎沒有人給出答案,所以我會告訴你我的猜測。 我希望以后有人對此進行補充。

我猜你的 jupyter notebook 服務器正在 Windows 主機上運行。 在多處理中,有三種不同的啟動方法。 讓我們關注spawn ,這是 windows 上的默認設置,以及fork ,這是 Unix 上的默認設置。

這是一個快速概述。

  • 產卵

    • (cpython) 交互式 shell - 總是引發錯誤
    • 作為腳本運行- 僅當您在if __name__ == '__main'__中嵌套多處理代碼時才可以
  • 叉子

    • 總是好的

例如,

import multiprocessing

def worker():
    """worker function"""
    print('Worker')
    return

if __name__ == '__main__':
    multiprocessing.set_start_method('spawn')
    jobs = []
    for i in range(5):
        p = multiprocessing.Process(target=worker)
        jobs.append(p)
        p.start()

此代碼在保存並作為腳本運行時有效,但在 python 交互式 shell 中輸入時會引發錯誤。 是 ipython 內核的實現,我的猜測是它使用了某種交互式 shell,因此不適合spawn (但請不要相信我)。


作為旁注,我將大致了解spawnfork的不同之處。 每個子進程在多處理中運行不同的 python 解釋器。 特別是,使用spawn ,子進程會啟動一個新的解釋器並從頭開始導入必要的模塊。 在交互式 shell 中很難導入代碼,因此可能會引發錯誤。

叉子是不同的。 使用fork,子進程復制主進程,包括python解釋器的大部分運行狀態,然后繼續執行。 此代碼將幫助您理解這個概念。

import os


main_pid = os.getpid()

os.fork()
print("Hello world(%d)" % os.getpid())  # print twice. Hello world(id1) Hello world(id2)

if os.getpid() == main_pid:
    print("Hello world(main process)")  # print once. Hello world(main process)

這在 MAC 上對我有用(不能在 Windows 上工作):

import multiprocessing as mp
mp_start_count = 0

if __name__ == '__main__':
    if mp_start_count == 0:
        mp.set_start_method('fork')
        mp_start_count += 1

將函數保存到單獨的 Python 文件中,然后重新導入函數。這樣應該可以正常工作。

我發現遵循Multi-processing example是最簡單的。

所以 ThreadPool 解決了我的問題。

from multiprocessing.pool import ThreadPool as Pool

def worker():
    """worker function"""
    print('Worker\n')
    return


pool = Pool(4)
for result in pool.map(worker, range(5)):
    pass    # or print diagnostics

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM