补丁中的线程和队列

时间:2018-11-06 15:42:02

标签: python multithreading

我有大约1000万个条目要处理。当前,我逐项检查条目并运行一个子例程,例如,当处理1000个条目时,我打开一个csv文件并将结果保存到其中。

for num, i in enumerate (some iterator)
       function(i)
       if num is multiple of 1000
              open file and save

在利用队列和线程处理时如何保存部分?现在,我将10个工厂条目放入队列中,并启动线程以运行该子例程。可以,但是我不能把头放在保存部分上。

put all entries in queue
for i in number of threads
    run function
    start thread

3 个答案:

答案 0 :(得分:0)

几件事。您将希望每个线程写入一个单独的文件,然后在最后合并文件。使用锁定机制可以起作用,但可能会导致您的应用程序性能回到单个线程,具体取决于您写入CSV的次数。

此处提供了一个创建池和队列的出色教程:

https://www.metachris.com/2016/04/python-threadpool/

并且:

Threading pool similar to the multiprocessing Pool?

最后,您将需要合并文件(如果需要),最好是在操作系统级别执行此操作,但是在python中,您可以执行以下操作:

filenames = ['file1.txt', 'file2.txt', ...]
with open('path/to/output/file', 'w') as outfile:
    for fname in filenames:
        with open(fname) as infile:
            for line in infile:
                outfile.write(line)

答案 1 :(得分:0)

这是假设您已经设置了所有其他线程

在初始化线程的地方,需要创建一个线程锁定对象

threadLock = threading.Lock()

然后在您正在编写的函数中执行以下操作:

for num, i in enumerate (some iterator)
    function(i)
    if num is multiple of 1000

        threadLock.acquire()
        #open file with an append
        #save
        #close file
        threadLock.release()

threadLock.acquire()可能需要放在if语句之前

在其他线程上锁定代码的某些部分或访问共享变量(如文件)时,它们“关门”,而另一个线程已经在使用它时,它们必须等待转过那扇门

答案 2 :(得分:0)

使用"secret sauce" of CPython threading-队列!

写入文件本质上是顺序的,因此您最好将一个线程负责所有编写。 让所有辅助线程将其结果推送到公共输出队列。 从此输出队列中读取单个编写器线程,然后 每隔1000个条目或在所有辅助线程完成后再写入csv。

通过这种方式,您可以避免需要锁定或之后合并部分文件的麻烦。


这是我建议的基本结构。它创建2500个条目,使它们具有5个线程,并在每10个结果之后输出:

import queue
import threading
SENTINEL = None

def worker(in_queue, out_queue):
    for n in iter(in_queue.get, SENTINEL):
        # print('task called: {n}'.format(n=n))
        out_queue.put(n*2)

def write(out_queue, chunksize=10):
    results = []
    for n in iter(out_queue.get, SENTINEL):
        results.append(n)
        if len(results) >= chunksize:
            print(results)
            results = []
    if len(results):
        # SENTINEL signals the worker threads are done.
        # print the remainder of the results
        print(results)

in_queue = queue.Queue()
out_queue = queue.Queue()
num_threads = 5

N = 2500
for i in range(N):
    in_queue.put(i)

for i in range(num_threads):
    # ad a SENTINEL to tell each worker to end
    in_queue.put(SENTINEL)

writer = threading.Thread(target=write, args=(out_queue,))
writer.start()
threads = [threading.Thread(target=worker, args=(in_queue, out_queue))
           for n in range(num_threads)]

for t in threads:
    t.start()

for t in threads:
    t.join()

# tell the writer to end
out_queue.put(SENTINEL)            
writer.join()

可打印

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
[20, 22, 24, 26, 28, 30, 32, 34, 36, 38]
[40, 42, 44, 46, 48, 50, 52, 54, 56, 58]
...
[4940, 4942, 4944, 4946, 4948, 4950, 4952, 4954, 4956, 4958]
[4960, 4962, 4964, 4966, 4968, 4970, 4972, 4974, 4976, 4978]
[4980, 4982, 4984, 4986, 4988, 4990, 4992, 4994, 4996, 4998]

请注意,打印的值可能不会按排序顺序显示。这取决于并发线程将结果推入out_queue的顺序。