我听说过“如果你想从并行应用程序中获得最大性能,你应该创建与你的计算机有CPU一样多的进程,并在每个进程中创建一些(多少?)线程”。< / p>
是真的吗?
我写了一段实现这个习语的代码:
import multiprocessing, threading
number_of_processes = multiprocessing.cpu_count()
number_of_threads_in_process = 25 # some constant
def one_thread():
# very heavyweight function with lots of CPU/IO/network usage
do_main_work()
def one_process():
for _ in range(number_of_threads_in_process):
t = threading.Thread(target=one_thread, args=())
t.start()
for _ in range(number_of_processes):
p = multiprocessing.Process(target=one_process, args=())
p.start()
这是对的吗?我的do_main_work
函数是否真的并行运行,不会遇到任何GIL问题?
谢谢。
答案 0 :(得分:2)
# very heavyweight function with lots of CPU/IO/network usage
由于 GIL ,很多 CPU 会受到影响,因此您只能从多个流程中受益。
GIL 和网络(实际上网络也是一种IO)不会受到太多影响,因为锁定将在 IO 操作完成后显式释放并再次获取。 CPython中有宏观定义:Py_BEGIN_ALLOW_THREADS
... Do some blocking I/O operation ...
Py_END_ALLOW_THREADS
由于 GIL 被用于包装代码,但性能仍然受到影响,但您仍然可以通过多个线程获得更好的性能。
最后 - 这是一般规则 - 不仅适用于Python:最佳线程/进程数取决于程序实际执行的操作。通常,如果它集中使用CPU,如果进程数大于CPU核心数,则几乎没有性能提升。例如,Gentoo文档说编译器的最佳线程数是CPU核心+ 1。
答案 1 :(得分:2)
这在很大程度上取决于你正在做什么。
请记住,在CPython中,一次只有一个线程可以执行Python字节码(因为GIL)。因此,对于CPython中的计算密集型问题,线程不会对您有所帮助。
分散可以并行完成工作的一种方法是使用multiprocessing.Pool
。默认情况下,这不会使用CPU具有核心的更多进程。使用更多的进程将主要让他们争夺资源(CPU,内存)而不是完成有用的工作。
但是利用多个处理器需要你有工作要做!换句话说,如果问题不能分成可以单独和并行计算的小块,那么许多CPU内核将没有多大用处。
此外,不是问题受到必须进行的计算量的限制。
计算机的RAM比CPU慢得多。如果您正在处理的数据集远大于CPU的缓存,则从RAM中读取数据并将结果返回到RAM可能会成为速度限制。这称为memory bound。
如果您正在处理的数据远远超过机器内存中的数据,那么您的程序将从磁盘上进行大量读写操作。与CPU相比,磁盘速度慢,而且与CPU相比,非常慢,因此您的程序变为I/O-bound。
答案 2 :(得分:0)
我认为每个进程使用的线程数太高。通常对于任何英特尔处理器,每个进程使用的线程数是2。内核数量从2(Intel core i3)到6(Intel core i7)不等。 )。因此,当所有进程都在运行时,最大线程数将为6 * 2 = 12。