繁体   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