Python,帮助并行化算法(尝试在线程池中包含线程池
我正在尝试将一些计算并行化,但我不明白为什么我的一个版本(我认为应该更快)比这个版本慢 简而言之,我有一个userid列表(大约200个)和一个placesId列表(大约200000个)。我需要为每对用户/位置计算一个分数。好事情 计算是完全独立的(取决于我们如何实现算法,甚至不需要返回结果) 我为此尝试了两种方法 第一种方法Python,帮助并行化算法(尝试在线程池中包含线程池,python,multithreading,performance,python-3.x,concurrent.futures,Python,Multithreading,Performance,Python 3.x,Concurrent.futures,我正在尝试将一些计算并行化,但我不明白为什么我的一个版本(我认为应该更快)比这个版本慢 简而言之,我有一个userid列表(大约200个)和一个placesId列表(大约200000个)。我需要为每对用户/位置计算一个分数。好事情 计算是完全独立的(取决于我们如何实现算法,甚至不需要返回结果) 我为此尝试了两种方法 第一种方法 拉动主线程中的所有位置和所有用户 循环遍历所有的user和spawn x线程(在我的例子中,我的小macbook 8似乎是最好的) 当所有的未来都完成后,我循环遍历所有的
def task(userId, placeIds):
connection = pool.getconn()
cursor = conn.cursor()
#loop through all the places and call makeCalculation(cur, userId, placeId)
pool.putconn(conn)
return results
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
futures = [ executor.submit(calculateScores,userId,placeId) for placeId in placeIds]
我必须做的另一个修改是calculateScores函数
def calculateScores(userId,placeId):
**connection = pool.getconn()
cursor = connecton.cursor()**
...
make a bunch of calculation by calling the database 1 or 2 times
pool.putconn(conn)
return [userId, placeId, score]
如您所见,因为现在calculateScores本身将在8//个线程上,因此我无法共享数据库连接,否则我将出现竞争条件错误(然后脚本将在4次中的3次中有1次崩溃)
这种方法,我认为会更快,但需要25分钟。。。。。(而不是使用简单for循环的10…)
我90%确信这会比较慢,因为现在每个任务都从池中获得一个数据库连接,这不知何故非常昂贵,因此速度较慢
有没有人能给我一些建议,让我的场景中的并行化发挥最大作用的最佳方式是什么
这是使任务返回结果的好主意吗?或者我应该在calculateScores函数中准备好后立即将它们插入数据库中吗
在线程池中有一个线程池是一种好的做法吗
我是否应该尝试实施一些多流程
谢谢大家!
在线程池中有一个线程池是一种好的做法吗
不,在您的情况下,单线程池就足够了,例如:
from concurrent.futures import ThreadPoolExecutor as Executor
from collections import deque
with Executor(max_workers=8) as executor:
deque(executor.map(calculateScores, userIds, placeIds), maxlen=0)
如果数据库是应用程序中的瓶颈(为了找出原因,您可以模拟db调用),即如果任务是i/O绑定的,那么线程可以提高时间性能(),因为可以在python本身的i/O(和其他阻塞操作系统)调用过程中或在C扩展(如用于CPython的db驱动程序)中释放GIL
如果数据库能够很好地处理并发访问,那么每个线程都可以使用自己的数据库连接。注意:8
线程可能比4
和16
线程都快——您需要测量它
时间性能可能在很大程度上取决于如何构造数据库操作。看
如果任务受CPU限制,例如,您为每个用户/位置id执行一些昂贵的纯Python计算,那么您可以尝试
ProcessPoolExecutor
而不是ThreadPoolExecutor
。确保进程之间输入/输出数据的复制不会主导计算本身。您知道GIL吗?我所知道的最好的解释是大卫·比兹利(David Beazley):我以为我做到了,但显然没有。他举的第一个例子就是为什么我的第二种方法比较慢。。。很明显,这是没有办法的?即使我开始在同一句话中使用进程-线程和Python。。。不幸的是,这项任务是由Java完成的,我认为使用python会更快(是这样的(Java版本为20分钟)),但我认为我可以用这种方法来推动它2@AlexGidan字体拙劣的工匠责备他的工具。Python+线程在很多工作中都很有用。
from concurrent.futures import ThreadPoolExecutor as Executor
from collections import deque
with Executor(max_workers=8) as executor:
deque(executor.map(calculateScores, userIds, placeIds), maxlen=0)