簡體   English   中英

在多個進程中使用deque對象

[英]Working with deque object across multiple processes

我正在嘗試減少大約100,000個條目讀取數據庫的處理時間,但是我需要將它們格式化為特定方式,為了做到這一點,我嘗試使用python的multiprocessing.map函數,該函數完美地工作,除了我似乎無法獲得任何形式的隊列引用來跨越它們。

我一直在使用來自填充隊列和管理python中的多處理的信息來指導我在多個進程中使用隊列,並使用帶有線程的全局變量來指導我跨線程使用全局變量。 我已經讓軟件工作了,但是當我在運行進程后檢查list / queue / dict / map長度時,它總是返回零

我寫了一個簡單的例子來說明我的意思:你必須將腳本作為文件運行, mapinitialize函數不能從解釋器中運行。

from multiprocessing import Pool
from collections import deque

global_q = deque()

def my_init(q):
    global global_q
    global_q = q
    q.append("Hello world")


def map_fn(i):
    global global_q
    global_q.append(i)


if __name__ == "__main__":
    with Pool(3, my_init, (global_q,)) as pool:
        pool.map(map_fn, range(3))
    for p in range(len(global_q)):
        print(global_q.pop())

理論上,當我使用pool函數將隊列對象引用從主線程傳遞給工作線程,然后使用給定函數初始化該線程的全局變量時,那么當我稍后從map函數將元素插入隊列時,對象引用仍然應該指向原始隊列對象引用(長話短說,一切都應該在同一個隊列中結束,因為它們都指向內存中的相同位置)。

所以,我希望:

Hello World
Hello World
Hello World
1
2
3

當然, 1, 2, 3是任意順序,但你在輸出上看到的是''

為什么當我將對象引用傳遞給pool函數時,沒有任何反應?

這是一個如何通過擴展multiprocessing.managers.BaseManager類來支持deque之間在進程之間共享內容的示例。

文檔中有關於創建自定義管理器的部分

import collections
from multiprocessing import Pool
from multiprocessing.managers import BaseManager


class DequeManager(BaseManager):
    pass

class DequeProxy(object):
    def __init__(self, *args):
        self.deque = collections.deque(*args)
    def __len__(self):
        return self.deque.__len__()
    def appendleft(self, x):
        self.deque.appendleft(x)
    def append(self, x):
        self.deque.append(x)
    def pop(self):
        return self.deque.pop()
    def popleft(self):
        return self.deque.popleft()

# Currently only exposes a subset of deque's methods.
DequeManager.register('DequeProxy', DequeProxy,
                      exposed=['__len__', 'append', 'appendleft',
                               'pop', 'popleft'])


process_shared_deque = None  # Global only within each process.


def my_init(q):
    global process_shared_deque  # Initialize module-level global.
    process_shared_deque = q
    q.append("Hello world")

def map_fn(i):
    process_shared_deque.append(i)  # deque's don't have a "put()" method.


if __name__ == "__main__":
    manager = DequeManager()
    manager.start()
    shared_deque = manager.DequeProxy()

    with Pool(3, my_init, (shared_deque,)) as pool:
        pool.map(map_fn, range(3))

    for p in range(len(shared_deque)):  # Show left-to-right contents.
        print(shared_deque.popleft())

輸出:

Hello world
0
1
2
Hello world
Hello world

您無法使用全局變量進行多重處理。

傳遞給函數多處理隊列。

from multiprocessing import Queue
queue= Queue() 

def worker(q):
    q.put(something)

您也可以體驗到代碼是正確的,但是當池創建單獨的進程時,即使錯誤也會被分開,因此您不會看到代碼不僅不起作用,而且它會引發錯誤。

輸出為''的原因是因為沒有任何內容附加到q / global_q。 如果它被追加,那么只有一些變量,可以稱為global_q,但它與你主線程中的global_q完全不同

嘗試在你想要多處理的函數內打印('Hello world'),你會自己看到,實際上根本沒有打印任何東西。 該進程只是在主線程之外,訪問該進程的唯一方法是通過多處理隊列。 您可以通過queue.put('something')和something = queue.get()訪問Queue

嘗試理解這段代碼,你會做得很好:

import multiprocessing as mp

shared_queue = mp.Queue() # This will be shared among all procesess, but you need to pass the queue as an argument in the process. You CANNOT use it as global variable. Understand that the functions kind of run in total different processes and nothing can really access them... Except multiprocessing.Queue - that can be shared across all processes.


def channel(que,channel_num):
    que.put(channel_num)

if __name__ == '__main__':
    processes = [mp.Process(target=channel, args=(shared_queue, channel_num)) for channel_num in range(8)]

    for p in processes:
        p.start()


    for p in processes: # wait for all results to close the pool
        p.join()

    for i in range(8): # Get data from Queue. (you can get data out of it at any time actually)
        print(shared_queue.get())

暫無
暫無

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

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