Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 剖析吉尔_Python_Multithreading_Profiling_Cython_Gil - Fatal编程技术网

Python 剖析吉尔

Python 剖析吉尔,python,multithreading,profiling,cython,gil,Python,Multithreading,Profiling,Cython,Gil,有没有一种方法可以描述python进程对GIL的使用情况?基本上,我想知道持有GIL的时间百分比。这个过程是单线程的 我的动机是用Cython编写一些代码,它使用nogil。理想情况下,我希望在多线程进程中运行它,但为了知道这是否可能是一个好主意,我需要知道GIL是否有大量的空闲时间 我发现,从8年前开始。唯一的答案是“不”。希望从那时起情况有所改变。我不知道有这样的工具 但是有一些启发式方法可以帮助您猜测使用多线程是否会有所帮助。正如您可能知道的,GIL将在IO操作期间释放,并且一些对本机代

有没有一种方法可以描述python进程对GIL的使用情况?基本上,我想知道持有GIL的时间百分比。这个过程是单线程的

我的动机是用Cython编写一些代码,它使用
nogil
。理想情况下,我希望在多线程进程中运行它,但为了知道这是否可能是一个好主意,我需要知道GIL是否有大量的空闲时间



我发现,从8年前开始。唯一的答案是“不”。希望从那时起情况有所改变。

我不知道有这样的工具

但是有一些启发式方法可以帮助您猜测使用多线程是否会有所帮助。正如您可能知道的,GIL将在IO操作期间释放,并且一些对本机代码的调用,特别是第三方本机模块。如果您没有太多这样的代码,那么多线程可能不会对您有所帮助

如果您确实有IO/本机代码,那么您可能需要尝试一下。根据代码库的不同,将整个过程转换为利用多线程可能需要大量工作,因此您可能希望尝试将多线程应用于您知道IO/本机代码正在被调用的部分,并进行测量以查看是否有任何改进


根据您的用例,多处理可以用于主要受CPU限制的情况。多处理确实会增加开销,因此对于持续时间相对较长(几秒或更长)的CPU受限任务,这通常是一种很好的方法。

完全出于偶然,我找到了一个工具,它可以做到这一点:

它实际上是在我发布问题后发布的

干得好,@chrisjbillington

>>> import sys, math
>>> import gil_load
>>> gil_load.init()
>>> gil_load.start(output = sys.stdout)
>>> for x in range(1, 1000000000):
...     y = math.log(x**math.pi)
[2017-03-15 08:52:26]  GIL load: 0.98 (0.98, 0.98, 0.98)
[2017-03-15 08:52:32]  GIL load: 0.99 (0.99, 0.99, 0.99)
[2017-03-15 08:52:37]  GIL load: 0.99 (0.99, 0.99, 0.99)
[2017-03-15 08:52:43]  GIL load: 0.99 (0.99, 0.99, 0.99)
[2017-03-15 08:52:48]  GIL load: 1.00 (1.00, 1.00, 1.00)
[2017-03-15 08:52:52]  GIL load: 1.00 (1.00, 1.00, 1.00)
<...>

>>> import sys, math
>>> import gil_load
>>> gil_load.init()
>>> gil_load.start(output = sys.stdout)
>>> for x in range(1, 1000000000):
...     with open('/dev/null', 'a') as f:
...         print(math.log(x**math.pi), file=f)

[2017-03-15 08:53:59]  GIL load: 0.76 (0.76, 0.76, 0.76)
[2017-03-15 08:54:03]  GIL load: 0.77 (0.77, 0.77, 0.77)
[2017-03-15 08:54:09]  GIL load: 0.78 (0.78, 0.78, 0.78)
[2017-03-15 08:54:13]  GIL load: 0.80 (0.80, 0.80, 0.80)
[2017-03-15 08:54:19]  GIL load: 0.81 (0.81, 0.81, 0.81)
[2017-03-15 08:54:23]  GIL load: 0.81 (0.81, 0.81, 0.81)
[2017-03-15 08:54:28]  GIL load: 0.81 (0.81, 0.81, 0.81)
[2017-03-15 08:54:33]  GIL load: 0.80 (0.80, 0.80, 0.80)
<...>
导入系统,数学 >>>导入gil_负载 >>>gil_load.init() >>>gil_加载启动(输出=系统标准输出) >>>对于范围(100000000)内的x: ... y=math.log(x**math.pi) GIL负荷:0.98(0.98,0.98,0.98) GIL负荷:0.99(0.99,0.99,0.99) GIL负荷:0.99(0.99,0.99,0.99) GIL负荷:0.99(0.99,0.99,0.99) GIL负荷:1.00(1.00,1.00,1.00) GIL负荷:1.00(1.00,1.00,1.00) >>>导入系统、数学 >>>导入gil_负载 >>>gil_load.init() >>>gil_加载启动(输出=系统标准输出) >>>对于范围(100000000)内的x: ... 将open('/dev/null',a')作为f: ... 打印(math.log(x**math.pi),文件=f) GIL负荷:0.76(0.76,0.76,0.76) GIL负荷:0.77(0.77,0.77,0.77) GIL负荷:0.78(0.78,0.78,0.78) GIL负荷:0.80(0.80,0.80,0.80) GIL负荷:0.81(0.81,0.81,0.81) GIL负荷:0.81(0.81,0.81,0.81) GIL负荷:0.81(0.81,0.81,0.81) GIL负荷:0.80(0.80,0.80,0.80)
如果您想知道GIL被占用了多少次,可以使用gdb断点。例如:

> cat gil_count_example.py
import sys
import threading
from threading import Thread

def worker():
    k=0
    for j in range(10000000):
        k+=j
    return

num_threads = int(sys.argv[1])
threads = []
for i in range(num_threads):
    t = Thread(target = worker)
    t.start()
    threads.append(t)

for t in threads:
    t.join()
对于3.X中断时间
take\u gil

> cgdb --args python3 gil_count_example.py 8 (gdb) b take_gil (gdb) ignore 1 100000000 (gdb) r (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x00007ffff7c85f10 in take_gil at Python-3.4.3/Python/ceval_gil.h:208 breakpoint already hit 1886 times 一个高效的穷人剖析器也可以用来分析我使用的函数中的墙时间

>./get_stacktrace--max=100--freq=10`/sbin/pidof python2` ... 292 71.92%扫描等待:PyThread获取锁定

>./get_stacktrace--max=100--freq=10`/sbin/pidof python3` ... 557 77.68%pthread_cond_timedwait:take_gil
除了第一句话,这并不能回答问题。特别是因为这个答案忽略了一种情况,即尽管OP明确提到多线程,但在没有任何IO发生的情况下多线程将是有用的。特别是没有任何理由在多进程而不是多线程中使用nogil运行cython代码。如果不涉及IO或本机(或者更确切地说是非Python)代码,多线程在什么情况下会有所帮助?顺便说一句,我没有看到这个问题提到任何关于IO的内容。我在David Beazley关于GIL的一次演讲中看到了他是如何描述GIL的:@denfromufa如果我的问题的答案在这个链接的某个地方,如果你把它作为一个答案发布,我将不胜感激。 > cgdb --args python2 gil_count_example.py 8 (gdb) b PyThread_acquire_lock (gdb) ignore 1 100000000 (gdb) r (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x00000039bacfd410 breakpoint already hit 1584561 times > ./get_stacktrace --max=100 --freq=10 `/sbin/pidof python2` ... 292 71.92% sem_wait:PyThread_acquire_lock > ./get_stacktrace --max=100 --freq=10 `/sbin/pidof python3` ... 557 77.68% pthread_cond_timedwait:take_gil