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