[英]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_THREADS
或MODE_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.