簡體   English   中英

循環中的python線程

[英]python threading in a loop

我有一個項目,需要一堆大型矩陣,並將它們存儲在約200 MB的文件中,以進行相互關聯(即FFT * conj(FFT))。 文件數量如此之多,以至於我不能只加載所有文件然后進行處理。 另一方面,根據需要讀取每個文件的速度比我想要的慢。

我到目前為止所擁有的是:

result=0
for i in xrange(N_files):
    f1 = file_reader(file_list[i])

    ############################################################################
    # here I want to have file_reader go start reading the next file I'll need #
    ############################################################################

    in_place_processing(f1)
    for j in xrange(i+1,N_files):
        f2 = file_reader(file_list[j])

        ##################################################################
        # here I want to have file_reader go start reading the next file #
        ##################################################################

        in_place_processing(f2)
        result += processing_function(f1,f2)

因此,基本上,我只想擁有兩個線程,每個線程將讀取一個文件,在我需要時(或在我要它后立即完成)將其提供給我,然后開始讀取下一個文件的時間我要。 file_reader返回的對象相當大且復雜,因此我不確定多處理是否是實現此目標的方法...

我已經閱讀了有關線程和隊列的知識,但似乎無法弄清楚我要求線程去讀取文件的部分,並且可以在程序執行的同時繼續進行。 我不想讓線程在后台簡單地從事他們的業務-我是否在這里錯過了一個細節,還是線程不是走的路?

以下是使用multiprocessing模塊的示例,該模塊將產生子進程以調用您的file_reader方法並將其結果排隊。 隊列在滿時應會阻塞,因此您可以使用QUEUE_SIZE常數控制要執行的QUEUE_SIZE

這利用了多進程通信的標准生產者/消費者模型,子進程充當了生產者,主線程是消費者。 類析構函數中的join方法調用可確保正確清理子進程資源。 出於說明目的,散布了一些打印聲明。

另外,我還為QueuedFileReader類添加了將工作分擔到工作線程或在主線程中運行的功能,而不是使用子進程進行比較。 這是通過在類初始化時分別將模式參數指定為MODE_THREADSMODE_SYNCHRONOUS完成的。

import multiprocessing as mp
import Queue
import threading
import time

QUEUE_SIZE = 2 #buffer size of queue

## Placeholder for your functions and variables
N_files = 10
file_list = ['file %d' % i for i in range(N_files)]

def file_reader(filename):
    time.sleep(.1)
    result = (filename,'processed')
    return result

def in_place_processing(f):
    time.sleep(.2)

def processing_function(f1,f2):
    print f1, f2
    return id(f1) & id(f2)

MODE_SYNCHRONOUS = 0  #file_reader called in main thread synchronously
MODE_THREADS = 1      #file_reader executed in worker thread
MODE_PROCESS = 2      #file_reader executed in child_process
##################################################
## Class to encapsulate multiprocessing objects.
class QueuedFileReader():
    def __init__(self, idlist, mode=MODE_PROCESS):
        self.mode = mode
        self.idlist = idlist
        if mode == MODE_PROCESS:
            self.queue = mp.Queue(QUEUE_SIZE)
            self.process = mp.Process(target=QueuedFileReader.worker,
                                      args=(self.queue,idlist))
            self.process.start()
        elif mode == MODE_THREADS:
            self.queue = Queue.Queue(QUEUE_SIZE)
            self.thread = threading.Thread(target=QueuedFileReader.worker,
                                           args=(self.queue,idlist))
            self.thread.start()

    @staticmethod
    def worker(queue, idlist):
        for i in idlist:
            queue.put((i, file_reader(file_list[i])))
            print id(queue), 'queued', file_list[i]
        queue.put('done')

    def __iter__(self):
        if self.mode == MODE_SYNCHRONOUS:
            self.index = 0
        return self

    def next(self):
        if self.mode == MODE_SYNCHRONOUS:
            if self.index == len(self.idlist): raise StopIteration
            q = (self.idlist[self.index],
                 file_reader(file_list[self.idlist[self.index]]))
            self.index += 1
        else:
            q = self.queue.get()
            if q == 'done': raise StopIteration
        return q

    def __del__(self):
        if self.mode == MODE_PROCESS:
            self.process.join()
        elif self.mode == MODE_THREADS:
            self.thread.join()

#mode = MODE_PROCESS
mode = MODE_THREADS
#mode = MODE_SYNCHRONOUS
result = 0
for i, f1 in QueuedFileReader(range(N_files),mode):

    in_place_processing(f1)

    for j, f2 in QueuedFileReader(range(i+1,N_files),mode):
        in_place_processing(f2)
        result += processing_function(f1,f2)

如果中間值太大而無法通過隊列,則可以在其自己的過程中執行外循環的每個迭代。 一個方便的方法是在下面的示例中的multiprocessing使用Pool類。

import multiprocessing as mp
import time

## Placeholder for your functions and variables
N_files = 10
file_list = ['file %d' % i for i in range(N_files)]

def file_reader(filename):
    time.sleep(.1)
    result = (filename,'processed')
    return result

def in_place_processing(f):
    time.sleep(.2)

def processing_function(f1,f2):
    print f1, f2
    return id(f1) & id(f2)

def file_task(file_index):
    print file_index
    f1 = file_reader(file_list[file_index])
    in_place_processing(f1)
    task_result = 0
    for j in range(file_index+1, N_files):
        f2 = file_reader(file_list[j])
        in_place_processing(f2)
        task_result += processing_function(f1,f2)
    return task_result



pool = mp.Pool(processes=None) #processes default to mp.cpu_count()
result = 0
for file_result in pool.map(file_task, range(N_files)):
    result += file_result
print 'result', result

#or simply
#result = sum(pool.map(file_task, range(N_files)))

暫無
暫無

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

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