Python 为什么只有一个工作线程的ThreadPoolExecutor仍然比正常执行快?

Python 为什么只有一个工作线程的ThreadPoolExecutor仍然比正常执行快?,python,multithreading,python-3.x,asynchronous,threadpoolexecutor,Python,Multithreading,Python 3.x,Asynchronous,Threadpoolexecutor,我正在使用这个库,它反过来使用来自标准库的,以便允许异步函数调用 明天调用decorator@threads(1)会使ThreadPoolExecutor与1个worker一起旋转 问题: 为什么使用1线程工作线程执行函数比按原样调用(例如,正常情况下)更快 为什么使用10个线程工作线程执行相同的代码要比仅使用1个甚至没有线程工作线程执行相同的代码慢 演示代码 不包括进口 注意:data文件夹包含18个文件,每700行随机文本 输出 0工人:0.0120秒 1个工人:0.0009秒 10名工

我正在使用这个库,它反过来使用来自标准库的,以便允许异步函数调用

明天调用decorator
@threads(1)
会使ThreadPoolExecutor与1个worker一起旋转

问题:
  • 为什么使用
    1线程工作线程执行函数比按原样调用(例如,正常情况下)更快
  • 为什么使用
    10个线程工作线程执行相同的代码要比仅使用1个甚至没有线程工作线程执行相同的代码慢
演示代码 不包括进口

注意:
data
文件夹包含18个文件,每700行随机文本

输出 0工人:0.0120秒
1个工人:0.0009秒
10名工人:0.0535秒

我所测试的
  • 我在后台运行了不同的程序(昨天运行了很多次,今天运行了几次),已经运行了好几次了。数字会改变,ofc,但顺序总是一样的。(即1是最快的,然后是0然后是10)
  • 我还尝试更改执行顺序(例如,移动do调用),以消除缓存作为一个因素,但仍然是一样的。
    • 结果表明,按照
      10
      1
      None
      的顺序执行,与其他每种排列相比,结果是不同的顺序(1最快,然后是10,然后是0)。结果表明,无论是<代码> do>代码>调用最后执行,都比它在第一次执行或中间执行时要慢得多。李>
结果(从@Dunes接收溶液后) 0工人:0.0122秒
1个工人:0.0214秒

10个worker:0.0296秒

当您调用一个异步函数时,它将返回一个“futures”对象(在本例中为
明天的实例)。这允许您提交所有作业,而无需等待它们完成。但是,永远不要真正等待工作完成。所以所有的
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中使用额外的线程通常会降低速度。这是因为全局解释器锁意味着无论CPU有多少个内核,只有一个线程可以处于活动状态

然而,由于你的工作受到限制,事情变得复杂了。更多的工作线程可能会加快速度。这是因为在多线程变体中,单个线程等待硬盘响应的时间可能比在不同线程之间切换上下文的时间要长


旁注,即使
openAsync1
openAsync10
都不等待作业完成,
do(openAsync10)
可能较慢,因为在提交新作业时需要更多线程之间的同步。

对于任何接近准确性能统计数据的内容来说,您的样本量可能太小。在测试诸如文件操作之类的事情时,还需要考虑缓存(在操作系统内)的影响。@ DalkFalCon,我已经运行代码超过Duin时间,不同的程序在后台运行(昨天运行了一堆,现在是一对夫妇)。数字会改变,ofc,但顺序总是一样的。我还尝试交换执行顺序,例如移动
do
调用。还是一样。你的测试似乎不正确。也就是说,异步变量不需要在结束测试之前等待所有工作完成。也就是说,您只是在计时设置所有工作线程所需的时间,而不是这些线程完成工作所需的时间。@Dunes我不确定我是否理解。。。你能用一些示例代码来解释我的错误吗?谢谢!按预期工作(并学习了python中异步的一些新知识):)
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/*"))