我正在使用此库Tomorrow,而该库又使用标准库中的ThreadPoolExecutor,以便允许异步函数调用。
调用装饰器@tomorrow.threads(1)
使用1个工作器旋转ThreadPoolExecutor。
1 thread worker
执行函数而不是按原样调用它(例如正常情况下)会更快?10 thread workers
代替1代表相同的代码执行相同的代码会更慢,甚至没有呢?导入已排除
def openSync(path: str):
for row in open(path):
for _ in row:
pass
@tomorrow.threads(1)
def openAsync1(path: str):
openSync(path)
@tomorrow.threads(10)
def openAsync10(path: str):
openSync(path)
def openAll(paths: list):
def do(func: callable)->float:
t = time.time()
[func(p) for p in paths]
t = time.time() - t
return t
print(do(openSync))
print(do(openAsync1))
print(do(openAsync10))
openAll(glob.glob("data/*"))
注意:data
文件夹包含18个文件,每700行随机文本。
0名工人:0.0120 秒
1名工人 0.0009 秒
10名员工 0.0535 秒
10
,1
,None
的顺序执行会产生不同的顺序(1最快,然后是10,然后是0)与其他所有排列相比。结果表明,无论最后执行do
调用,都会比先执行或在中间执行时慢得多。 0名工人:0.0122 秒
1名工人:0.0214 秒
10名工人:0.0296 秒
答案 0 :(得分:1)
当您调用其中一个异步函数时,它会返回一个“期货”对象(在这种情况下为tomorrow.Tomorrow
的实例)。这使您可以提交所有作业,而无需等待它们完成。但是,永远不要等待工作完成。所以do(openAsync1)
所做的就是设置所有作业需要多长时间(应该非常快)。要获得更准确的测试,您需要执行以下操作:
def openAll(paths: list):
def do(func: callable)->float:
t = time.time()
# do all jobs if openSync, else start all jobs if openAsync
results = [func(p) for p in paths]
# if openAsync, the following waits until all jobs are finished
if func is not openSync:
for r in results:
r._wait()
t = time.time() - t
return t
print(do(openSync))
print(do(openAsync1))
print(do(openAsync10))
openAll(glob.glob("data/*"))
在python中使用其他线程通常会减慢速度。这是因为全局解释器锁定意味着只有1个线程可以处于活动状态,无论CPU具有多少核心。
然而,由于你的工作是IO约束,事情变得复杂。更多工作线程可能加快速度。这是因为单个线程可能花费更多时间等待硬盘驱动器响应,而不是在多线程变体中各个线程之间的上下文切换之间丢失。
旁注,即使openAsync1
和openAsync10
都没有等待作业完成,do(openAsync10)
可能会更慢,因为在提交新作业时需要线程之间更多同步。