use*_*619 5 python multithreading file
我有很少的文件驻留在服务器上,我试图实现一个多线程进程来提高性能,我读了一个教程,但实现它的问题很少,
这是文件,
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()
Run Code Online (Sandbox Code Playgroud)
如何使用线程类和队列实现?
我从下面的类开始,但不知道如何将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()
Run Code Online (Sandbox Code Playgroud)
aba*_*ert 28
你正在混合两种不同的解决方案.
如果要为每个文件创建专用的工作线程,则不需要任何队列.如果你想创建一个线程池和文件的队列,你不希望通过inpfile
和outfile
该run
方法; 你想把它们放在队列中的每个作业中.
你如何在两者之间做出选择?好了,第一显然是简单的,但如果你有,比如说,1000页要复制的文件,你最终会创造1000个线程,为更多的线程比你想创建,并远远超过线程并行拷贝数操作系统将能够处理.线程池允许您创建8个线程,并在队列中放置1000个作业,并且它们将根据需要分配给线程,因此一次运行8个作业.
让我们从解决方案1开始,解决方案1是每个文件的专用工作线程.
首先,如果你没有与子类化结婚Thread
,那么这里真的没有理由这样做.您可以将target
函数和args
元组传递给默认构造函数,然后该run
方法将target(*args)
完全按照您的意愿执行.所以:
t = threading.Thread(target=workermethod, args=(inpfile, outfile))
Run Code Online (Sandbox Code Playgroud)
这就是你所需要的.当每个线程运行时,它将调用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()
Run Code Online (Sandbox Code Playgroud)
无论哪种方式,我建议使用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)
Run Code Online (Sandbox Code Playgroud)
现在,解决方案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)
Run Code Online (Sandbox Code Playgroud)
然后通过将一个单独传递queue
给所有线程来启动线程:
q = queue.Queue
threadpool = [ThreadUrl(q) for i in range(poolsize)]
Run Code Online (Sandbox Code Playgroud)
并提交这样的工作:
q.put((inpfile, outfile))
Run Code Online (Sandbox Code Playgroud)
如果您要使用线程池进行认真的工作,您可能需要考虑使用强大,灵活,简单和优化的实现,而不是自己编写代码.例如,您可能希望能够取消作业,很好地关闭队列,加入整个池而不是逐个加入线程,进行批处理或智能负载平衡等.
如果您使用的是Python 3,则应该查看标准库ThreadPoolExecutor
.如果您遇到Python 2,或者无法弄清楚Future
,那么您可能需要查看模块中ThreadPool
隐藏的类multiprocessing
.这两者都具有从多线程切换到多处理的优势(例如,事实证明,您需要与IO一起进行并行化的一些CPU限制工作)是微不足道的.你也可以搜索PyPI,你会发现其他多个好的实现.
作为旁注,您不希望调用队列queue
,因为这会影响模块名称.而且,有一些东西被称为workermethod
实际上是一个自由函数而不是一个方法,这有点令人困惑.
最后,如果你所做的只是复制文件,你可能不想在文本模式下阅读,或者逐行阅读.事实上,你可能根本不想自己实现它; 只需使用相应的复制功能shutil
.您可以非常轻松地使用上述任何方法.例如,而不是这样:
t = threading.Thread(target=workermethod, args=(inpfile, outfile))
Run Code Online (Sandbox Code Playgroud)
做这个:
t = threading.Thread(target=shutil.copyfile, args=(inpfile, outfile))
Run Code Online (Sandbox Code Playgroud)
事实上,您的整个程序看起来可以替换为:
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()
Run Code Online (Sandbox Code Playgroud)