簡體   English   中英

Python:多處理代碼非常慢

[英]Python: Multiprocessing code is very slow

我拉.8一氣呵成百萬的記錄(這是一個時間過程),從mongodb使用pymongo並對其執行某些操作。

我的代碼如下所示。

    proc = []
    for rec in cursor: # cursor has .8 million rows 
            print cnt
            cnt = cnt + 1
            url =  rec['urlk']
            mkptid = rec['mkptid']
            cii = rec['cii']

            #self.process_single_layer(url, mkptid, cii)


            proc = Process(target=self.process_single_layer, args=(url, mkptid, cii))
            procs.append(proc)
            proc.start()

             # complete the processes
    for proc in procs:
        proc.join()

process_single_layer是一個基本上從雲下載urls並本地存儲的功能。

現在的問題是,下載過程很慢,因為它必須命中URL。 而且由於記錄量巨大,因此要處理1k行,因此需要6分鍾。

為了減少時間,我想實現Multiprocessing 但是很難看到上面的代碼有什么區別。

請建議我如何在這種情況下提高性能。

首先,您需要計算文件中的所有行,然后生成固定數量的進程(最好與處理器內核的數量匹配),並通過隊列(每個進程一個)將等於total_number_of_rows / number_of_cores 這種方法的思想是將這些行的處理划分為多個進程,從而實現並行性。

一種動態找出內核數的方法是:

import multiprocessing as mp
cores_count = mp.cpu_count()

避免初始行數可以做的一點改進是,通過創建隊列列表來循環添加一行,然后在其上應用循環迭代器。

一個完整的例子:

import queue
import multiprocessing as mp
import itertools as itools

cores_count = mp.cpu_count()


def dosomething(q):

    while True:

        try:
            row = q.get(timeout=5)
        except queue.Empty:
            break

    # ..do some processing here with the row

    pass

if __name__ == '__main__':
    processes
    queues = []

    # spawn the processes
    for i in range(cores_count):
        q = mp.Queue()
        queues.append(q)
        proc = Process(target=dosomething, args=(q,))
        processes.append(proc)

    queues_cycle = itools.cycle(queues)
    for row in cursor:
        q = next(queues_cycle)
        q.put(row)

    # do the join after spawning all the processes
    for p in processes:
        p.join()

在這種情況下使用池更容易。

隊列不是必需的,因為您無需在生成的進程之間進行通信。 我們可以使用Pool.map分配工作量。

Pool.imapPool.imap_unordered在塊大小較大時可能會更快。 Pool.starmaphttps : Pool.starmap如果需要,可以使用Pool.starmap並擺脫元組拆包。

from multiprocessing import Pool

def process_single_layer(data):
    # unpack the tuple and do the processing
    url, mkptid, cii = data
    return "downloaded" + url

def get_urls():
    # replace this code: iterate over cursor and yield necessary data as a tuple
    for rec in range(8): 
            url =  "url:" + str(rec)
            mkptid = "mkptid:" + str(rec)
            cii = "cii:" + str(rec)
            yield (url, mkptid, cii)

#  you can come up with suitable process count based on the number of CPUs.
with Pool(processes=4) as pool:
    print(pool.map(process_single_layer, get_urls()))

暫無
暫無

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

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