Ipython 笔记本上的多核和多线程
Multicore and multithread on Ipython Notebook
我目前正在 python 中使用 threading 函数并得到以下信息:
In [1]:
import threading
threading.activeCount()
Out[1]:
4
现在在我的终端上,我使用 lscpu 并了解到每个核心有 2 个线程,我可以访问 4 个核心:
kitty@FelineFortress:~$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Thread(s) per core: 2
Core(s) per socket: 4
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 60
Stepping: 3
CPU MHz: 800.000
BogoMIPS: 5786.45
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 8192K
NUMA node0 CPU(s): 0-7
因此,我应该有超过 4 个线程可以访问。是否有 python 函数可以用来增加我正在使用的内核数量(例如)以获得超过 4 个线程?或者甚至在启动 ipython notebook 时在终端上键入如下内容:
ipython notebook n_cores=3
您可以使用 multiprocessing 来允许 Python 使用多核。一个重要的警告:您在 Python 会话之间传递的所有数据都必须是可挑选的或通过继承传递,并且在 Windows 上生成一个新的 Python 实例,而在 Unix 系统上它可以分叉。这对 Windows 系统有显着的性能影响。
使用多处理的基本 example 如下来自 "Python Module of the Week":
import multiprocessing
def worker():
"""worker function"""
print 'Worker'
return
if __name__ == '__main__':
jobs = []
for i in range(5):
p = multiprocessing.Process(target=worker)
jobs.append(p)
p.start()
执行时输出:
Worker
Worker
Worker
Worker
Worker
多处理允许您在不同的内核上进行独立计算,允许 CPU 绑定的任务以很少的开销执行,比传统进程执行得更快。
您还应该意识到 Python 中的线程不会提高性能。它的存在是为了方便(例如在长时间计算期间保持 GUI 的响应能力)。原因是由于 Python 的全局解释器锁,或 GIL.
,这些不是本机线程
2018 年 2 月更新
这个还是很适用的,而且在可预见的将来。 Cpython 实现使用以下 definition 进行引用计数:
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
值得注意的是,这 不是 线程安全的,因此必须实现全局解释器锁以仅允许一个线程执行 Python 对象以避免数据导致内存问题的比赛。
除了多处理(这需要 Windows 上的解释器的完整副本,而不是 fork,这使得它非常慢并且无法提高性能)。
赛通
最简单的解决方案是 Cython。简单地 cdef 一个函数,没有任何内部对象,并使用 with nogil
关键字释放 GIL。
取自 documentation 的一个简单示例,向您展示了如何释放并临时重新启用 GIL:
from cython.parallel import prange
cdef int func(Py_ssize_t n):
cdef Py_ssize_t i
for i in prange(n, nogil=True):
if i == 8:
with gil:
raise Exception()
elif i == 4:
break
elif i == 2:
return i
使用不同的解释器
CPython 有 GI,而 Jython 和 IronPython 没有。要小心,因为许多用于高性能计算的 C 库可能无法与 IronPython 或 Jython 一起工作(SciPy 曾尝试过 IronPython 支持,但很久以前就放弃了,它将不适用于现代 Python 版本)。
使用 MPI4Py
MPI,即消息传递接口,是一种用于 C 和 C++ 等语言的高性能接口。它允许高效的并行计算,MPI4Py 为 Python 创建 MPI 绑定。为了提高效率,您应该只将 MPI4Py 与 NumPy 数组一起使用。
他们 documentation 的一个例子是:
from mpi4py import MPI
import numpy
def matvec(comm, A, x):
m = A.shape[0] # local rows
p = comm.Get_size()
xg = numpy.zeros(m*p, dtype='d')
comm.Allgather([x, MPI.DOUBLE],
[xg, MPI.DOUBLE])
y = numpy.dot(A, xg)
return y
我目前正在 python 中使用 threading 函数并得到以下信息:
In [1]:
import threading
threading.activeCount()
Out[1]:
4
现在在我的终端上,我使用 lscpu 并了解到每个核心有 2 个线程,我可以访问 4 个核心:
kitty@FelineFortress:~$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Thread(s) per core: 2
Core(s) per socket: 4
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 60
Stepping: 3
CPU MHz: 800.000
BogoMIPS: 5786.45
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 8192K
NUMA node0 CPU(s): 0-7
因此,我应该有超过 4 个线程可以访问。是否有 python 函数可以用来增加我正在使用的内核数量(例如)以获得超过 4 个线程?或者甚至在启动 ipython notebook 时在终端上键入如下内容:
ipython notebook n_cores=3
您可以使用 multiprocessing 来允许 Python 使用多核。一个重要的警告:您在 Python 会话之间传递的所有数据都必须是可挑选的或通过继承传递,并且在 Windows 上生成一个新的 Python 实例,而在 Unix 系统上它可以分叉。这对 Windows 系统有显着的性能影响。
使用多处理的基本 example 如下来自 "Python Module of the Week":
import multiprocessing
def worker():
"""worker function"""
print 'Worker'
return
if __name__ == '__main__':
jobs = []
for i in range(5):
p = multiprocessing.Process(target=worker)
jobs.append(p)
p.start()
执行时输出:
Worker
Worker
Worker
Worker
Worker
多处理允许您在不同的内核上进行独立计算,允许 CPU 绑定的任务以很少的开销执行,比传统进程执行得更快。
您还应该意识到 Python 中的线程不会提高性能。它的存在是为了方便(例如在长时间计算期间保持 GUI 的响应能力)。原因是由于 Python 的全局解释器锁,或 GIL.
,这些不是本机线程2018 年 2 月更新
这个还是很适用的,而且在可预见的将来。 Cpython 实现使用以下 definition 进行引用计数:
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
值得注意的是,这 不是 线程安全的,因此必须实现全局解释器锁以仅允许一个线程执行 Python 对象以避免数据导致内存问题的比赛。
除了多处理(这需要 Windows 上的解释器的完整副本,而不是 fork,这使得它非常慢并且无法提高性能)。
赛通
最简单的解决方案是 Cython。简单地 cdef 一个函数,没有任何内部对象,并使用 with nogil
关键字释放 GIL。
取自 documentation 的一个简单示例,向您展示了如何释放并临时重新启用 GIL:
from cython.parallel import prange
cdef int func(Py_ssize_t n):
cdef Py_ssize_t i
for i in prange(n, nogil=True):
if i == 8:
with gil:
raise Exception()
elif i == 4:
break
elif i == 2:
return i
使用不同的解释器
CPython 有 GI,而 Jython 和 IronPython 没有。要小心,因为许多用于高性能计算的 C 库可能无法与 IronPython 或 Jython 一起工作(SciPy 曾尝试过 IronPython 支持,但很久以前就放弃了,它将不适用于现代 Python 版本)。
使用 MPI4Py
MPI,即消息传递接口,是一种用于 C 和 C++ 等语言的高性能接口。它允许高效的并行计算,MPI4Py 为 Python 创建 MPI 绑定。为了提高效率,您应该只将 MPI4Py 与 NumPy 数组一起使用。
他们 documentation 的一个例子是:
from mpi4py import MPI
import numpy
def matvec(comm, A, x):
m = A.shape[0] # local rows
p = comm.Get_size()
xg = numpy.zeros(m*p, dtype='d')
comm.Allgather([x, MPI.DOUBLE],
[xg, MPI.DOUBLE])
y = numpy.dot(A, xg)
return y