Python 绩效差异

Python 绩效差异,python,performance,multiprocessing,python-multithreading,Python,Performance,Multiprocessing,Python Multithreading,有人能解释为什么代码1比代码2好,或者相反: 一些数据:具有4核的计算机,需要执行8个独立任务,每个TAK需要大量处理、循环、计算等: 代码1:进程+线程 results = multiprocessing.Queue() p1 = multiprocessing.Process(target=bigTask1, args=(some_arguments, results)) p2 = multiprocessing.Process(target=bigTask2, args=(some_a

有人能解释为什么代码1比代码2好,或者相反:

一些数据:具有4核的计算机,需要执行8个独立任务,每个TAK需要大量处理、循环、计算等:

代码1:进程+线程

results = multiprocessing.Queue()


p1 = multiprocessing.Process(target=bigTask1, args=(some_arguments, results))
p2 = multiprocessing.Process(target=bigTask2, args=(some_arguments, results))
p3 = multiprocessing.Process(target=bigTask3, args=(some_arguments, results))
p4 = multiprocessing.Process(target=bigTask4, args=(some_arguments, results))


p5 = threading.Thread(target=bigTask5, args=(some_arguments, results))
p6 = threading.Thread(target=bigTask6, args=(some_arguments, results))
p7 = threading.Thread(target=bigTask7, args=(some_arguments, results))
p8 = threading.Thread(target=bigTask8, args=(some_arguments, results))

p1.daemon = True
p2.daemon = True
p3.daemon = True
p4.daemon = True
p5.daemon = True
p6.daemon = True
p7.daemon = True
p8.daemon = True

p1.start()
p2.start()
p3.start()
p4.start()
p5.start()
p6.start()
p7.start()
p8.start()


pool_pr += [p1]
pool_pr += [p2]
pool_pr += [p3]
pool_pr += [p4]
pool_pr += [p5]
pool_pr += [p6]
pool_pr += [p7]
pool_pr += [p8]

for p in  pool_pr:
    p.join()
代码2:仅处理

results = multiprocessing.Queue()


p1 = multiprocessing.Process(target=bigTask1, args=(some_arguments, results))
p2 = multiprocessing.Process(target=bigTask2, args=(some_arguments, results))
p3 = multiprocessing.Process(target=bigTask3, args=(some_arguments, results))
p4 = multiprocessing.Process(target=bigTask4, args=(some_arguments, results))


p5 = multiprocessing.Process(target=bigTask5, args=(some_arguments, results))
p6 = multiprocessing.Process(target=bigTask6, args=(some_arguments, results))
p7 = multiprocessing.Process(target=bigTask7, args=(some_arguments, results))
p8 = multiprocessing.Process(target=bigTask8, args=(some_arguments, results))

p1.daemon = True
p2.daemon = True
p3.daemon = True
p4.daemon = True
p5.daemon = True
p6.daemon = True
p7.daemon = True
p8.daemon = True

p1.start()
p2.start()
p3.start()
p4.start()
p5.start()
p6.start()
p7.start()
p8.start()


pool_pr += [p1]
pool_pr += [p2]
pool_pr += [p3]
pool_pr += [p4]
pool_pr += [p5]
pool_pr += [p6]
pool_pr += [p7]
pool_pr += [p8]

for p in  pool_pr:
    p.join()

我主要关心的是,如果我只有4个内核可用,那么使用4个进程+4个线程是否会带来任何好处??每次强制所有4个内核工作(4个进程)+(4个进程)是否更好???

如果您没有内存限制,那么我将使用代码2。它更简单,如果你在另一台计算机上运行它,可以扩展到8个内核。

如果你没有内存限制,那么我会使用代码2。它更简单,如果在不同的计算机上运行,可以扩展到8个内核。

取决于您是否使用了超线程或硬盘

如果您有超线程,8个进程比4个进程快,因为您可以同时运行它们。不过,在这种情况下不要使用线程

如果使用硬盘或其他速度较慢的存储介质,则可以使用线程并获得更高的吞吐量,因为线程可以在等待获取数据时切换


如果你没有,我会安排工作人员,让python来处理其余的工作。

取决于你是否有超读功能或者你是否在使用硬盘

如果您有超线程,8个进程比4个进程快,因为您可以同时运行它们。不过,在这种情况下不要使用线程

如果使用硬盘或其他速度较慢的存储介质,则可以使用线程并获得更高的吞吐量,因为线程可以在等待获取数据时切换


如果两者都没有,我会安排工作人员,让python来处理其余的工作。

我觉得,您误解了multiprocessing.Process模式。这并不意味着您将“bigTask1”管理到第一个处理器,将“bigTask2”管理到第二个处理器。这意味着python要求内核在可访问的处理器上分配工作负载,而不是向运行GIL的一个处理器的堆中添加线程。无论如何,在不同的处理器上分发并不便宜,因为同步、重新整合结果需要更多的开销


因此,您需要测试这两种方法,以确定哪种方法更快/更少地消耗资源。事实证明,多处理是一个很好的机会。进程的效率不如运行所有使用线程的进程。

我觉得,您误解了多处理。进程模式。这并不意味着您将“bigTask1”管理到第一个处理器,将“bigTask2”管理到第二个处理器。这意味着python要求内核在可访问的处理器上分配工作负载,而不是向运行GIL的一个处理器的堆中添加线程。无论如何,在不同的处理器上分发并不便宜,因为同步、重新整合结果需要更多的开销

因此,您需要测试这两种方法,以确定哪种方法更快/更少地消耗资源。事实证明,这是一个很好的机会,即多处理。处理的效率低于运行所有使用线程的效率。

每个TAK都需要大量的处理、循环、计算等

鉴于此,由于GIL,您根本不应该使用线程。一次只能执行一个线程,因此不会获得任何性能优势。正如其他人所说,线程只有在主要执行I/O时才有用

使用
multiprocessing.Process
将允许您在所有可用的CPU之间进行适当的扩展,这正是您所需要的。但是,它还增加了启动进程以及在父进程和子进程之间复制需要发送给工作进程的数据的开销。根据您需要在每个辅助进程中执行的工作所需的时间和需要复制的数据量,数据复制开销有时可能是程序中最慢的部分,以至于它使得多处理比仅以单线程/进程方式进行计算要慢

此外,您可能会也可能不会真正看到使用8个进程比使用4个进程的好处。正如其他人所说,这取决于您是否有超线程处理器。在这种情况下,我建议使用
多处理.Pool
而不是8个
多处理.Process
对象,这样您就可以轻松地在4个和8个进程之间切换,并测量程序对每个数字的执行情况:

pool = multiprocessing.Pool(4)  # or 8. Try both.

out_list = []
targets = [bigTask1, bigTask2, bigTask3, bigTask4,
           bigTask5, bigTask6, bigTask6, bigTask8]
for t in targets:
    out_list.append(pool.apply_async(t, args=(some_arguments))   

# You don't need a queue if you're using a pool. Just `return`
# the result from the worker function.
results = [r.get() for r in out_list]
每个TAK都需要大量的处理、循环、计算等

鉴于此,由于GIL,您根本不应该使用线程。一次只能执行一个线程,因此不会获得任何性能优势。正如其他人所说,线程只有在主要执行I/O时才有用

使用
multiprocessing.Process
将允许您在所有可用的CPU之间进行适当的扩展,这正是您所需要的。但是,它还增加了启动进程以及在父进程和子进程之间复制需要发送给工作进程的数据的开销。根据您需要在每个辅助进程中执行的工作所需的时间和需要复制的数据量,数据复制开销有时可能是程序中最慢的部分,以至于它使得多处理比仅以单线程/进程方式进行计算要慢

此外,您可能会也可能不会真正看到使用8个进程比使用4个进程的好处。正如其他人所说,这取决于您是否有超线程处理器。在这种情况下,我建议使用
多处理.Pool
而不是8个
多处理.Process
对象,这样您就可以轻松地在4个和8个进程之间切换,并测量程序对每个数字的执行情况:

pool = multiprocessing.Pool(4)  # or 8. Try both.

out_list = []
targets = [bigTask1, bigTask2, bigTask3, bigTask4,
           bigTask5, bigTask6, bigTask6, bigTask8]
for t in targets:
    out_list.append(pool.apply_async(t, args=(some_arguments))   

# You don't need a queue if you're using a pool. Just `return`
# the result from the worker function.
results = [r.get() for r in out_list]
A.