Nar*_*ser 57 python multithreading
问:因为python使用"GIL"是python能够同时运行其单独的线程吗?
信息:
看完这个我离开的时候相当不确定的蟒蛇是否是能够把多核处理器的优势.就像python一样,认为它缺乏如此强大的能力感觉真的很奇怪.所以感觉不确定,我决定在这里问.如果我编写一个多线程的程序,它是否能够在多个内核上同时执行?
Sin*_*ion 52
答案是"是的,但......"
但是当你使用常规线程进行并发时,cPython不能.
您既可以使用类似的东西multiprocessing
,celery
也mpi4py
可以将并行工作拆分为另一个流程;
或者你可以使用像Jython或IronPython这样的东西来使用没有GIL的替代解释器.
一个更软的解决方案是使用不与GIL相遇的库来执行繁重的CPU任务,例如numpy
可以在不保留GIL的情况下进行繁重的工作,因此其他python线程可以继续.您也可以ctypes
这种方式使用库.
如果你没有进行CPU绑定工作,你可以完全忽略GIL问题(种类),因为python在等待IO时不会获取GIL.
nin*_*cko 33
Python 线程无法利用许多内核.这是由于在python(cPython)的C实现中称为GIL(全局解释器锁)的内部实现细节,几乎可以肯定你使用它.
解决方法是为此目的开发的multiprocessing
模块http://www.python.org/dev/peps/pep-0371/.
文档:http://docs.python.org/library/multiprocessing.html
(或者使用并行语言.)
小智 11
正如之前的答案所述 - 这取决于“cpu 或 i/o 限制?”的答案,
还取决于“线程或多处理?”的答案:
示例在 Raspberry Pi 3B 1.2GHz 4 核和 Python3.7.3 上运行
- (运行其他进程,包括 htop )
典型结果:
. 启动 4000 个 io 绑定线程周期
。顺序运行时间:39.15秒
。4个线程并行运行时间:18.19秒
。2 个线程并行 - 两次运行时间:20.61 秒
典型结果:
. 启动 1000000 个仅 cpu 线程周期
。顺序运行时间:9.39秒
。4个线程并行运行时间:10.19秒
。2 个线程并行两次 - 运行时间:9.58 秒
典型结果:
. 开始 4000 个 io 绑定处理周期
。顺序运行时间:39.74 秒
。4 个进程并行运行时间:17.68 秒
。2 个进程并行两次 - 运行时间:20.68 秒
典型结果:
. 启动 1000000 个仅 cpu 处理周期
。顺序运行时间:9.24秒
。4 个进程并行运行时间:2.59 秒
。2 个进程并行两次 - 运行时间: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))
Run Code Online (Sandbox Code Playgroud)
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))
Run Code Online (Sandbox Code Playgroud)
Ned*_*der 10
CPython(Python的经典和流行的实现)不能同时具有多个执行Python字节码的线程.这意味着计算绑定程序将只使用一个核心.C扩展(例如numpy)内发生的I/O操作和计算可以同时运行.
Python的其他实现(例如Jython或PyPy)可能表现不同,我对它们的细节不太清楚.
通常的建议是使用许多进程而不是许多线程.
示例代码在我的 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)
Run Code Online (Sandbox Code Playgroud)
结果:
$ python 1.py
Sequential run time: 3.69 seconds
Parallel run time: 4.82 seconds
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
82397 次 |
最近记录: |