如何在multiprocessing.dummy.Pool中分别命名线程?

时间:2018-12-03 05:38:56

标签: python multithreading python-multithreading

我想为multiprocessing.dummy.Pool中的线程命名,以便当我从主线程调用threading.enumerate()时可以查看其所有名称。调用pool.apply_async以便能够命名线程时,是否可以应用关键字?我更愿意在创建时命名它们,而不是从tester函数中命名它们,只是为了保持清洁。

例如,如果我有以下示例代码:

import multiprocessing.dummy
from time import sleep
import threading

def tester():
    sleep(2)
    print("running \n")

def run_conc(number_of_threads, fxn):
    pool = multiprocessing.dummy.Pool(processes=number_of_threads)
    for thread in range(number_of_threads):
        pool.apply_async(tester)
    print(threading.enumerate(), "\n")
    pool.close()
    pool.join()

run_conc(3, tester)

当我运行它时,我收到输出:

[<_MainThread(MainThread, started 140735632434048)>, <Thread(SockThread, started daemon 123145521917952)>, <DummyProcess(Thread-1, started daemon 123145527246848)>, <DummyProcess(Thread-2, started daemon 123145532502016)>, <DummyProcess(Thread-3, started daemon 123145537757184)>, <Thread(Thread-4, started daemon 123145543012352)>, <Thread(Thread-5, started daemon 123145548267520)>, <Thread(Thread-6, started daemon 123145553522688)>] 

running 
running 
running 

我希望能够在该线程列表中命名这3个虚拟线程,以便我可以识别出哪一个。还是有一种方法可以在concurrent.futures内部使用,而我应该使用它呢?

3 个答案:

答案 0 :(得分:1)

在您调用pool.apply_async或其他池方法时(但在实例化该池之前),未创建池中的工作线程。调用池方法使用池中的现有线程。

在没有操纵源的情况下,无法在初始化时命名线程。您的选择是:

  • 重命名工作线程 池已准备好实例化
  • 用于修补特定命名模板的猴子修补池内部

第一个选项易于实现,您只需迭代池实例的._pool属性并更改所包含线程的.name

from multiprocessing.pool import ThreadPool as Pool


if __name__ == '__main__':

    pool = Pool(4)
    print([w.name for w in pool._pool])
    # ['Thread-1', 'Thread-2', 'Thread-3', 'Thread-4']

    for w in pool._pool:
        w.name = w.name.replace('Thread', 'ThreadPoolWorker')

    print([w.name for w in pool._pool])
    # ['ThreadPoolWorker-1', 'ThreadPoolWorker-2', 'ThreadPoolWorker-3', 'ThreadPoolWorker-4']

    pool.close()
    pool.join()

请注意,我在这里使用multiprocessing.pool.ThreadPool,只是为了遵守下面第二个选项中的示例,因为multiprocessing.dummy.Pool只是ThreadPool的包装。


对于第二个选项,可以使用包装器为工作线程ThreadPool.Process修补工厂功能,扩展默认名称'Thread-%d'(%d填充为一个计数器),其名称更有意义,例如“ ThreadPoolWorker”。

# threadpool.py
# Module patching the name of worker-threads within ThreadPool

__all__ = ['ThreadPool']

from functools import wraps
from multiprocessing.pool import ThreadPool


def rename_worker(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        w = fn(*args, **kwargs)
        w.name = w.name.replace('Thread', 'ThreadPoolWorker')
        return w
    return wrapper


ThreadPool.Process = staticmethod(rename_worker(ThreadPool.Process))

用法:

from threadpool import ThreadPool as Pool


if __name__ == '__main__':

    pool = Pool(4)
    print([w.name for w in pool._pool])
    # ['ThreadPoolWorker-1', 'ThreadPoolWorker-2', 'ThreadPoolWorker-3', 'ThreadPoolWorker-4']
    pool.close()
    pool.join()

答案 1 :(得分:0)

如果您可以编辑线程名称,那么按照以下代码片段进行操作即可

from multiprocessing import Pool,Queue
import threading

thread_names = Queue()
num_process = 4
for e in ['A','B','C','D']:
    thread_names.put('Thread-{}'.format(e))

def initializer(q):
    thread_name = q.get()
    threading.current_thread().name = thread_name

if __name__ == '__main__':
    pool = Pool(num_process=4,initializer=initializer,initargs=(threadnames,))

答案 2 :(得分:0)

好的,我发现可以通过为tester分配一个值来从threading.current_thread().name函数中更改线程名称。但是,如果有人在创建pool.apply_async行后就知道如何设置线程名称,那将不胜感激。