Multithreading Python 3 concurrent.futures和每线程初始化
在Python 3中,是否可以在concurrent.futures.ThreadPoolExecutor的上下文中使用Thread的子类,以便在处理许多工作项之前对它们进行单独初始化 我想使用方便的API实现一段同步文件和S3对象的代码,如果相应的S3对象不存在或不同步,则每个工作项都是一个要同步的文件。我希望每个工作线程首先进行一些初始化,例如设置boto3.session.session。然后,工作线程池将准备好处理数千个可能要同步的工作项文件 顺便说一句,如果一个线程由于某种原因死亡,那么期望自动创建一个新线程并将其添加回池中是否合理Multithreading Python 3 concurrent.futures和每线程初始化,multithreading,python-3.x,concurrent.futures,Multithreading,Python 3.x,Concurrent.futures,在Python 3中,是否可以在concurrent.futures.ThreadPoolExecutor的上下文中使用Thread的子类,以便在处理许多工作项之前对它们进行单独初始化 我想使用方便的API实现一段同步文件和S3对象的代码,如果相应的S3对象不存在或不同步,则每个工作项都是一个要同步的文件。我希望每个工作线程首先进行一些初始化,例如设置boto3.session.session。然后,工作线程池将准备好处理数千个可能要同步的工作项文件 顺便说一句,如果一个线程由于某种原因死亡,那
免责声明:与Python相比,我更熟悉Java的多线程框架。因此,我的问题的一个简单解决方案似乎是使用在下面的模型中存储每个线程会话,只是一个随机整数。我想这可能不是最干净的,但现在它可以。下面是Python 3.5.1的模型:
import time
import threading
import concurrent.futures
import random
import logging
logging.basicConfig(level=logging.DEBUG, format='(%(threadName)-0s) %(relativeCreated)d - %(message)s')
x = [0.1, 0.1, 0.2, 0.4, 1.0, 0.1, 0.0]
mydata = threading.local()
def do_work(secs):
if 'session' in mydata.__dict__:
logging.debug('re-using session "{}"'.format(mydata.session))
else:
mydata.session = random.randint(0,1000)
logging.debug('created new session: "{}"'.format(mydata.session))
time.sleep(secs)
logging.debug('slept for {} seconds'.format(secs))
return secs
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
y = executor.map(do_work, x)
print(list(y))
生成以下输出,表明会话确实是每个线程的本地会话,并且可以重用:
(Thread-1) 29 - created new session: "855"
(Thread-2) 29 - created new session: "58"
(Thread-3) 30 - created new session: "210"
(Thread-1) 129 - slept for 0.1 seconds
(Thread-1) 130 - re-using session "855"
(Thread-2) 130 - slept for 0.1 seconds
(Thread-2) 130 - re-using session "58"
(Thread-3) 230 - slept for 0.2 seconds
(Thread-3) 230 - re-using session "210"
(Thread-3) 331 - slept for 0.1 seconds
(Thread-3) 331 - re-using session "210"
(Thread-3) 331 - slept for 0.0 seconds
(Thread-1) 530 - slept for 0.4 seconds
(Thread-2) 1131 - slept for 1.0 seconds
[0.1, 0.1, 0.2, 0.4, 1.0, 0.1, 0.0]
关于日志记录的次要注意事项:为了在IPython笔记本中使用此功能,需要稍微修改日志记录设置,因为IPython已经设置了根日志记录程序。更可靠的日志记录设置是:
IN_IPYNB = 'get_ipython' in vars()
if IN_IPYNB:
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
for h in logger.handlers:
h.setFormatter(logging.Formatter(
'(%(threadName)-0s) %(relativeCreated)d - %(message)s'))
else:
logging.basicConfig(level=logging.DEBUG, format='(%(threadName)-0s) %(relativeCreated)d - %(message)s')
事实并非如此,ThreadPoolExecutor通常在线程少于任务时重用线程。在这种情况下,使用同一线程的上下文可能导致意外行为。