我正在使用cytpes包装 C api。api 函数之一允许您注册回调。我使用CFUNCTYPEto 来指定函数的类型,并CFUNCTYPE从我的 python 库的用户提供的 python 函数中创建一个实例,然后我将其传递给 C 函数(使用ctypesapi调用)。
我知道ctypes调用释放GIL. 我想知道当 C 库函数调用我的 python 回调函数时会发生什么。是否ctypes重新获得GIL?
该文件说:
注意:
CFUNCTYPE()只要在 C 代码中使用对象,请确保保留对对象的引用。ctypes没有,如果你不这样做,它们可能会被垃圾收集,在进行回调时会导致程序崩溃。另外,请注意,如果在 Python 控制之外创建的线程中调用回调函数(例如,通过调用回调的外部代码),则ctypes在每次调用时都会创建一个新的虚拟 Python 线程。这种行为在大多数情况下是正确的,但它意味着存储的值threading.local不会在不同的回调中存活,即使这些调用是从同一个 C 线程进行的。
它没有说任何关于GIL. 是不是说一切都由我来处理?
I'm writing a python program that includes a c++ module (.so, using boost.python).
I'm starting several python threads that run a c++ function.
This is how the C++ code looks like:
#include <boost/python.hpp>
using namespace boost;
void f(){
// long calculation
// call python function
// long calculation
}
BOOST_PYTHON_MODULE(test)
{
python::def("f", &f);
}
Run Code Online (Sandbox Code Playgroud)
And the python code:
from test import f
t1 = threading.Thread(target=f)
t1.setDaemon(True)
t1.start()
print "Still running!"
Run Code Online (Sandbox Code Playgroud)
I encounter a problem: the "Still running!" …
在 Python 中,我有一个列表列表作为输入:
input = [[0,1,2],[0,3,4,5],[0,6]]
Run Code Online (Sandbox Code Playgroud)
实际上,子列表的数量有数万个。每个子列表的长度可能相差很大,从零或一个值到数百个值。
我想将输入数据作为某种 2D 结构传递给将处理它的 Cython 模块。我希望在多个核心上处理数据,因此我使用prangewith nogil=True:
from cython.parallel import prange
cpdef int my_func(long[:,:] arr):
cdef int i,j
for i in prange(arr.shape[0], nogil=True):
for j in range(arr.shape[1]):
# Do something
pass
return 42
Run Code Online (Sandbox Code Playgroud)
我看到以下解决方案:
my_func以接受列表的列表。问题是部分代码是在没有 GIL 的情况下执行的,因此无法访问 python 对象。有没有人对如何解决这个问题有建议,最好有代码?
在这个问题的上下文中什么是“运行时”?(/sf/ask/273038461/)
我试图了解 python 运行时由什么组成。我的猜测是:
现在,如果这是正确的,我们是否可以说 python 中的多处理创建了多个运行时并且一个 python 进程是我们可以直接与运行时相关联的东西?(我认为这是正确的选择)
或者,每个 python 线程都有自己的堆栈,与父进程在相同的 GIL 和内存空间上工作,可以被称为具有单独的运行时?
或者,不管有多少线程或进程正在运行,它都会在一个运行时下运行?
简单来说,Python 上下文中运行时的定义是什么?
PS:我理解线程和进程之间的区别。GIL:我理解这些影响,但我不理解。
根据我在研究 Python GIL 时的理解,一次只能执行一个线程(谁持有锁)。然而,如果这是真的,那么为什么这段代码只需要 3 秒的执行时间,而不是 15 秒呢?
import threading
import time
def worker():
"""thread worker function"""
time.sleep(3)
print 'Worker'
for i in range(5):
t = threading.Thread(target=worker)
t.start()
Run Code Online (Sandbox Code Playgroud)
根据对线程的直觉,我原以为这需要 3 秒,但确实如此。但是在了解了 GIL 并且可以立即执行一个线程之后,现在我看这段代码并想,为什么不花 15 秒?
我想我一定错过了什么;这似乎是正确的,但我看不出有什么方法可以做到这一点。
假设你在 Python 中有一个纯函数:
from math import sin, cos
def f(t):
x = 16 * sin(t) ** 3
y = 13 * cos(t) - 5 * cos(2*t) - 2 * cos(3*t) - cos(4*t)
return (x, y)
Run Code Online (Sandbox Code Playgroud)
是否有一些内置功能或库提供某种类型的包装器,可以在函数执行期间释放 GIL?
在我的脑海中,我在想一些事情
from math import sin, cos
from somelib import pure
@pure
def f(t):
x = 16 * sin(t) ** 3
y = 13 * cos(t) - 5 * cos(2*t) - 2 * cos(3*t) - cos(4*t)
return (x, y)
Run Code Online (Sandbox Code Playgroud)
为什么我认为这可能有用?
因为目前只对 I/O 密集型程序有吸引力的多线程,一旦这些功能长期运行就会变得有吸引力。做类似的事情 …
在 version 3.8 中更改: max_workers 的默认值更改为 min(32, os.cpu_count() + 4)。此默认值为 I/O 绑定任务保留至少 5 个工作线程。它最多使用 32 个 CPU 核心来执行释放 GIL 的 CPU 密集型任务。它避免了在多核机器上隐式使用大量资源。
根据我对 GIL 的理解,基于线程的并发仅适用于 I/O 绑定任务。对于 CPU 密集型任务,基于线程的并发是不可能的,这意味着对于 CPU 密集型任务,GIL 仅强制单线程执行。我的理解似乎与 中的粗体行相矛盾ThreadPoolExecutor。我在这里误解了什么?
此外,什么是
释放GIL
意思是?CPU 密集型任务不会保留 GIL(除非它被抢占)吗?
从这个答案来看,我怀疑这与
大部分时间都花在旨在发布 GIL 的外部库上(如 NumPy)
这是否意味着只要线程在某些专门设计的“旨在释放 GIL”的外部库中执行 CPU 密集型任务,CPU 密集型任务的基于线程的并发实际上是可能的?
我正在包装一个执行阻塞操作(选择)的C函数,然后处理传入的消息.我的理解是,当一个C函数要阻塞时,在允许其他线程运行的同时调用它的正确方法是:
Py_BEGIN_ALLOW_THREADS
blocking_function();
Py_END_ALLOW_THREADS
Run Code Online (Sandbox Code Playgroud)
但是,它发生此函数将回调指针作为参数.在处理由C函数预处理的传入消息时调用此回调.我已经成功地将这个回调包装在一个调用的函数中PyEval_CallObject(),允许我传递一个Python回调.
现在我正在添加线程支持,我想知道是否可以同时:
这会导致问题吗?如果是这样,有办法吗?
谢谢.
我正在尝试改进扫描文件中的恶意代码的脚本.我们在文件中有一个正则表达式模式列表,每行一个模式.这些正则表达式适用于grep,因为我们当前的实现基本上是一个bash脚本find\grep combo.bash脚本在我的基准测试目录上需要358秒.我能够编写一个在72秒内执行此操作的python脚本,但希望进一步提高.首先,我将发布基本代码然后调试我尝试过:
import os, sys, Queue, threading, re
fileList = []
rootDir = sys.argv[1]
class Recurser(threading.Thread):
def __init__(self, queue, dir):
self.queue = queue
self.dir = dir
threading.Thread.__init__(self)
def run(self):
self.addToQueue(self.dir)
## HELPER FUNCTION FOR INTERNAL USE ONLY
def addToQueue(self, rootDir):
for root, subFolders, files in os.walk(rootDir):
for file in files:
self.queue.put(os.path.join(root,file))
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
self.queue.put(-1)
class Scanner(threading.Thread):
def __init__(self, queue, patterns):
self.queue = queue …Run Code Online (Sandbox Code Playgroud) 我的django应用程序将django模型保存到远程数据库.有时保存是突发性的.为了将应用程序的主线程(*thread_A*)从将多个对象保存到数据库的时间中解放出来,我想到了将模型对象转移到一个单独的线程(*thread_B*)使用collections.deque并具有*thread_B*save他们顺序.
但我不确定这个计划.save()返回新数据库条目的id,因此只有在数据库响应后才会"结束",这是在事务结束时.
难道django.db.models.Model.save()真的阻止GIL -wise并释放其他的Python线程中的交易?
gil ×10
python ×10
boost-python ×1
c++ ×1
callback ×1
ctypes ×1
cython ×1
django ×1
python-3.x ×1
runtime ×1
string ×1
terminology ×1
transactions ×1