我有很少的文件驻留在服务器上,我试图实现一个多线程过程以提高性能,我读了一个教程但很少有问题实现它,
以下是文件
filelistread = ['h:\\file1.txt', \
'h:\\file2.txt', \
'h:\\file3.txt', \
'h:\\file4.txt']
filelistwrte = ['h:\\file1-out.txt','h:\\file2-out.txt','h:\\file3-out.txt','h:\\file4-out.txt']
def workermethod(inpfile, outfile):
f1 = open(inpfile,'r')
f2 = open(outfile,'w')
x = f1.readlines()
for each in x:
f2.write(each)
f1.close()
f2.close()
如何使用线程类和队列实现?
我从下面的类开始,但不知道如何将inpfile和outputfile传递给run方法。赞赏任何输入
class ThreadUrl(threading.Thread):
def __init__(self,queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
item = self.queue.get()
答案 0 :(得分:28)
你正在混合两种不同的解决方案。
如果要为每个文件创建专用的工作线程,则不需要任何队列。如果要创建线程池和文件队列,则不要希望将inpfile
和outfile
传递给run
方法;你想把它们放在队列中的每个工作中。
你如何在两者之间做出选择?好吧,第一个显然更简单,但如果你有1000个要复制的文件,你最终会创建1000个线程,这比你想要创建的线程多,并且线程比并行副本多得多操作系统将能够处理。线程池允许您创建8个线程,并在队列中放置1000个作业,并且它们将根据需要分配给线程,因此一次运行8个作业。
让我们从解决方案1开始,每个文件都有一个专用的工作线程。
首先,如果您未与子类Thread
结婚,那么这里真的没有理由这样做。您可以将target
函数和args
元组传递给默认构造函数,然后run
方法将完全按照您的需要执行target(*args)
。{1}}。所以:
t = threading.Thread(target=workermethod, args=(inpfile, outfile))
这就是你所需要的一切。当每个线程运行时,它将调用workermethod(inpfile, outfile)
然后退出。
但是,如果你做由于某种原因想要继承Thread
,你可以。您可以在构建时传递inpfile
和outfile
,并且run
方法只需workermethod
修改为使用self.inpfile
和self.outfile
而不是参数。像这样:
class ThreadUrl(threading.Thread):
def __init__(self, inpfile, outfile):
threading.Thread.__init__(self)
self.inpfile, self.outfile = inpfile, outfile
def run(self):
f1 = open(self.inpfile,'r')
f2 = open(self.outfile,'w')
x = f1.readlines()
for each in x:
f2.write(each)
f1.close()
f2.close()
无论哪种方式,我建议使用with
语句而不是显式open
和close
,并删除readlines
(不必要地将整个文件读入内存),除非你需要处理真正旧版本的Python:
def run(self):
with open(self.inpfile,'r') as f1, open(self.outfile,'w') as f2:
for line in f1:
f2.write(line)
现在,解决方案2:一个线程池和一个队列。
同样,你不需要这里的子类;两种做事方式之间的差异与解决方案1中的差异相同。但是坚持你已经开始的子类设计,你需要这样的东西:
class ThreadUrl(threading.Thread):
def __init__(self,queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
inpfile, outfile = self.queue.get()
workermethod(inpfile, outfile)
然后通过将一个queue
传递给所有线程来启动线程:
q = queue.Queue
threadpool = [ThreadUrl(q) for i in range(poolsize)]
并提交这样的工作:
q.put((inpfile, outfile))
如果您要使用线程池进行认真的工作,您可能需要考虑使用强大,灵活,简单和优化的实现,而不是自己编写代码。例如,您可能希望能够取消作业,很好地关闭队列,加入整个池而不是逐个加入线程,进行批处理或智能负载平衡等。
如果您使用的是Python 3,则应该查看标准库ThreadPoolExecutor
。如果您遇到Python 2,或者无法弄清楚Future
,您可能需要查看隐藏在ThreadPool
模块中的multiprocessing
类。这两者都具有从多线程切换到多处理的优势(例如,事实证明,您需要与IO一起进行并行化的一些CPU限制工作)是微不足道的。你也可以search PyPI,你会发现其他多个好的实现。
作为旁注,您不希望调用队列queue
,因为这会影响模块名称。另外,有一个名为workermethod
的东西实际上是一个自由函数而不是一个方法,这有点令人困惑。
最后,如果你所做的只是复制文件,你可能不想在文本模式下阅读,也不想逐行阅读。事实上,你可能根本不想自己实现它;只需使用shutil
中的相应复制功能即可。您可以非常轻松地使用上述任何方法。例如,而不是:
t = threading.Thread(target=workermethod, args=(inpfile, outfile))
这样做:
t = threading.Thread(target=shutil.copyfile, args=(inpfile, outfile))
事实上,看起来您的整个程序可以替换为:
threads = [threading.Thread(target=shutil.copyfile, args=(inpfile, outfile))
for (inpfile, outfile) in zip(filelistread, filelistwrte)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()