繁体   English   中英

为什么多线程和单线程之间没有执行时间差异

[英]Why is there no execution time difference between multithreading and singlethreading

我正在尝试学习python语言及其概念。 我写了一些代码来玩多线程。 但我注意到多线程和单线程之间没有执行时间差异。

运行脚本的机器有4个核心/线程。

 def get_tokens(file_name,map):
    print(file_name)
    counter = 0
    with open(file_name,'r',encoding='utf-8-sig') as f:
        for line in f:
            item = json.loads(line,encoding='utf-8')
            if 'spot' in item and item['sid'] == 4663:
                counter+=1
                if counter == 500:
                    break
                tokens = nltk.word_tokenize(item['spot'],language='english')
                for token in tokens:
                    if token not in map:
                        map[token] = 1
                    else:
                        map[token] = map[token] + 1;

 start_time = time.time()
 map = dict();
 with ThreadPoolExecutor(max_workers=3) as executor:
    for file in FileProcessing.get_files_in_directory('D:\\Raw Data'):
        future = executor.submit(FileProcessing.get_tokens, file, map)

 end_time = time.time()
 print("Elapsed time was %g seconds" % (end_time - start_time))

原始数据中的每个文件大小都大于25 MB。 所以我认为它们之间必须存在差异。 但事实并非如此。 为什么? 我在代码或多线程概念中犯了错误吗?

CPython(Python的标准实现)不支持在不同的CPU上进行多线程处理。 因此,您确实可以拥有多个线程,但它们都将在同一个CPU上运行,并且您不会对CPU绑定进程进行速度改进(您可以使用I / O绑定进程)。

原因是臭名昭着的GIL(全球翻译锁定)。 Python的核心不是线程安全的,因为它进行垃圾收集的方式,因此它使用锁,这意味着访问python对象的线程一个接一个地运行。

在您的特定情况下,您正在进行一些I / O和一些处理。 在python中进行多处理时会产生很大的开销,而I / O的速度增益无法补偿(读取文件的时间与处理文件的时间相比可能很小)。

如果你需要做真正的多线程,请看Cython(不要与CPython混淆)和“no_gil”,或c-extensions,或多处理模块。

Python具有全局解释器锁(GIL) ,它可以防止同一个python进程中的两个执行线程同时执行。 因此,虽然python线程在单个进程中为您提供了多个控制路径,但多个控制路径无法在多核计算机上同时执行。 另一种方法是使用python 多处理框架 ,它实际上会创建单独的进程,然后让进程通过进程间通信(IPC)进行通信。 您也可以尝试使用ProcessPoolExecutor来生成多个进程,因此您不会遇到GIL问题

GIL注释是正确的,但是此代码更可能是IO绑定而不是CPU绑定。

即使你使用了像C或Java这样的东西,你仍然在通过串行接口读取文件,所以除非你不能处理100-300 MB / s的JSON,否则你不会看到线程带来的性能优势。

@DevShark确实说过你会看到IO绑定进程的好处,但它比这复杂得多。 对于高延迟的并发网络连接,这往往更多。 在这种情况下,您将在磁盘上进行IO绑定,而不是进程(您不是在等待远程响应),因此并行性将无济于事。

如果你是CPU限制的,有真正的线程,并且正在使用旋转磁盘,你仍然需要仔细调整缓冲区大小。 10ms寻道时间可以杀死你,因此你需要使用缓冲区大小的缓冲区读取,如果你想要高磁盘吞吐量的话。 使用100MB / s磁盘,寻道时间为10ms,我会使用10MB缓冲区,但这仍然意味着你花费10%的时间在磁盘上寻找。 我也会协调我的阅读,所以一次只能读一个读者。

问题是可以通过线程来改进代码。 如果代码是串行的,并且有一件事在一条直线上发生,那么无论你有多少线程,代码都将运行相同的代码。 但是,如果代码可以分支并同时执行动作a和动作b,那么它将会。 仔细观察您的代码,似乎没有分支,至少我不知道。

您的代码受CPU限制 - 默认情况下,多线程将保留在单个CPU中。 您可以使用多处理程序包 ,它允许您创建子进程并基本上绕过GIL(全局解释器锁)。 当然,这只有在你拥有多个CPU的情况下才有用。 我不认为这个用例需要多个进程的开销。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM