问题:因为python使用“GIL”是python能够同时运行它的单独线程吗?
的信息:
在阅读this后,我不确定python是否能够利用多核处理器。就像python一样,认为它缺乏如此强大的能力感觉真的很奇怪。所以感觉不确定,我决定在这里问。如果我编写一个多线程的程序,它是否能够在多个内核上同时执行?
答案 0 :(得分:44)
答案是“是的,但是......”
但是当您使用常规线程进行并发时,cPython无法实现。
您可以使用multiprocessing
,celery
或mpi4py
之类的内容将并行工作拆分为另一个流程;
或者您可以使用Jython或IronPython之类的内容来使用没有GIL的替代解释器。
更软的解决方案是使用不与GIL相遇的库来执行繁重的CPU任务,例如numpy
可以在不保留GIL的情况下执行繁重的工作,因此其他python线程可以继续。您也可以这种方式使用ctypes
库。
如果你没有进行CPU绑定工作,你可以完全忽略GIL问题(种类)因为python在等待IO时不会获取GIL。
答案 1 :(得分:29)
Python 线程无法利用多个核心。这是由于在python(cPython)的C实现中称为GIL(全局解释器锁)的内部实现细节,几乎可以肯定你使用它。
解决方法是为此目的而开发的 multiprocessing
模块http://www.python.org/dev/peps/pep-0371/。
文档:http://docs.python.org/library/multiprocessing.html
(或使用并行语言。)
答案 2 :(得分:10)
CPython(Python的经典和流行的实现)不能同时有多个线程执行Python字节码。这意味着计算绑定程序将只使用一个核心。 C扩展中发生的I / O操作和计算(例如numpy)可以同时运行。
Python的其他实现(例如Jython或PyPy)可能表现不同,我对其细节不太清楚。
通常的建议是使用许多进程而不是许多线程。
答案 3 :(得分:2)
如之前的答案所述 - 这取决于“cpu 或 i/o 绑定?”的答案,
还有“线程或多处理?”的答案:
示例在 Raspberry Pi 3B 1.2GHz 4 核和 Python3.7.3 上运行
--(其他进程正在运行,包括 htop )
典型结果:
.启动 4000 个循环的 io-bound 线程
.顺序运行时间:39.15 秒
. 4线程并行运行时间:18.19秒
. 2 个线程并行 - 两次运行时间:20.61 秒
典型结果:
.启动 1000000 个循环的 cpu-only 线程
.顺序运行时间:9.39 秒
. 4线程并行运行时间:10.19秒
. 2 个线程并行两次 - 运行时间:9.58 秒
典型结果:
.启动 4000 个循环的 io-bound 处理
.顺序 - 运行时间:39.74 秒
. 4 进程并行 - 运行时间:17.68 秒
. 2 procs 并行两次 - 运行时间:20.68 秒
典型结果:
.启动 1000000 个循环的 cpu-only 处理
.顺序运行时间:9.24 秒
. 4 进程并行 - 运行时间:2.59 秒
. 2 procs 并行两次 - 运行时间:4.76 秒
compare_io_multiproc.py:
#!/usr/bin/env python3
# Compare single proc vs multiple procs execution for io bound operation
"""
Typical Result:
Starting 4000 cycles of io-bound processing
Sequential - run time: 39.74 seconds
4 procs Parallel - run time: 17.68 seconds
2 procs Parallel twice - run time: 20.68 seconds
"""
import time
import multiprocessing as mp
# one thousand
cycles = 1 * 1000
def t():
with open('/dev/urandom', 'rb') as f:
for x in range(cycles):
f.read(4 * 65535)
if __name__ == '__main__':
print(" Starting {} cycles of io-bound processing".format(cycles*4))
start_time = time.time()
t()
t()
t()
t()
print(" Sequential - run time: %.2f seconds" % (time.time() - start_time))
# four procs
start_time = time.time()
p1 = mp.Process(target=t)
p2 = mp.Process(target=t)
p3 = mp.Process(target=t)
p4 = mp.Process(target=t)
p1.start()
p2.start()
p3.start()
p4.start()
p1.join()
p2.join()
p3.join()
p4.join()
print(" 4 procs Parallel - run time: %.2f seconds" % (time.time() - start_time))
# two procs
start_time = time.time()
p1 = mp.Process(target=t)
p2 = mp.Process(target=t)
p1.start()
p2.start()
p1.join()
p2.join()
p3 = mp.Process(target=t)
p4 = mp.Process(target=t)
p3.start()
p4.start()
p3.join()
p4.join()
print(" 2 procs Parallel twice - run time: %.2f seconds" % (time.time() - start_time))
compare_cpu_multiproc.py
#!/usr/bin/env python3
# Compare single proc vs multiple procs execution for cpu bound operation
"""
Typical Result:
Starting 1000000 cycles of cpu-only processing
Sequential run time: 9.24 seconds
4 procs Parallel - run time: 2.59 seconds
2 procs Parallel twice - run time: 4.76 seconds
"""
import time
import multiprocessing as mp
# one million
cycles = 1000 * 1000
def t():
for x in range(cycles):
fdivision = cycles / 2.0
fcomparison = (x > fdivision)
faddition = fdivision + 1.0
fsubtract = fdivision - 2.0
fmultiply = fdivision * 2.0
if __name__ == '__main__':
print(" Starting {} cycles of cpu-only processing".format(cycles))
start_time = time.time()
t()
t()
t()
t()
print(" Sequential run time: %.2f seconds" % (time.time() - start_time))
# four procs
start_time = time.time()
p1 = mp.Process(target=t)
p2 = mp.Process(target=t)
p3 = mp.Process(target=t)
p4 = mp.Process(target=t)
p1.start()
p2.start()
p3.start()
p4.start()
p1.join()
p2.join()
p3.join()
p4.join()
print(" 4 procs Parallel - run time: %.2f seconds" % (time.time() - start_time))
# two procs
start_time = time.time()
p1 = mp.Process(target=t)
p2 = mp.Process(target=t)
p1.start()
p2.start()
p1.join()
p2.join()
p3 = mp.Process(target=t)
p4 = mp.Process(target=t)
p3.start()
p4.start()
p3.join()
p4.join()
print(" 2 procs Parallel twice - run time: %.2f seconds" % (time.time() - start_time))
答案 4 :(得分:1)
线程共享进程并且进程在核心上运行,但是您可以使用python的多处理模块在单独的进程中调用您的函数并使用其他核心,或者您可以使用子进程模块,它可以运行您的代码和非也是python代码。
答案 5 :(得分:1)
示例代码在我的ubuntu 14.04,python 2.7 64位上占用了所有4个内核。
import time
import threading
def t():
with open('/dev/urandom') as f:
for x in xrange(100):
f.read(4 * 65535)
if __name__ == '__main__':
start_time = time.time()
t()
t()
t()
t()
print "Sequential run time: %.2f seconds" % (time.time() - start_time)
start_time = time.time()
t1 = threading.Thread(target=t)
t2 = threading.Thread(target=t)
t3 = threading.Thread(target=t)
t4 = threading.Thread(target=t)
t1.start()
t2.start()
t3.start()
t4.start()
t1.join()
t2.join()
t3.join()
t4.join()
print "Parallel run time: %.2f seconds" % (time.time() - start_time)
结果:
$ python 1.py
Sequential run time: 3.69 seconds
Parallel run time: 4.82 seconds
答案 6 :(得分:0)
我将脚本转换为Python3并在我的Raspberry Pi 3B +上运行它:
import time
import threading
def t():
with open('/dev/urandom', 'rb') as f:
for x in range(100):
f.read(4 * 65535)
if __name__ == '__main__':
start_time = time.time()
t()
t()
t()
t()
print("Sequential run time: %.2f seconds" % (time.time() - start_time))
start_time = time.time()
t1 = threading.Thread(target=t)
t2 = threading.Thread(target=t)
t3 = threading.Thread(target=t)
t4 = threading.Thread(target=t)
t1.start()
t2.start()
t3.start()
t4.start()
t1.join()
t2.join()
t3.join()
t4.join()
print("Parallel run time: %.2f seconds" % (time.time() - start_time))
python3 t.py
Sequential run time: 2.10 seconds
Parallel run time: 1.41 seconds
对我来说,并行运行更快。
答案 7 :(得分:0)
在Raspberry Pi 3 Model B修订版1.2上
pi@raspberrypi:~/smart/cpu $ python2 core.py
Sequential run time: 2.34 seconds
Parallel run time: 1.74 seconds
pi@raspberrypi:~/smart/cpu $ python2.7 core.py
Sequential run time: 2.34 seconds
Parallel run time: 1.74 seconds
pi@raspberrypi:~/smart/cpu $ python3 core.py
Sequential run time: 2.32 seconds
Parallel run time: 1.74 seconds
pi@raspberrypi:~/smart/cpu $ python3.4 core.py
Sequential run time: 2.32 seconds
Parallel run time: 1.74 seconds
答案 8 :(得分:0)
range(10000)
Sequential run time: 228.56 seconds
Parallel run time: 147.03 seconds
Raspberry Pi 3 B+
Raspbian v 4.19.57-v7+ #1244
Python v. 3.5.3
GCC v. 6.3
在顺序过程中,CPU利用率达到25%, 在并行过程中,CPU会达到100%