关闭线程上的泡菜负载阻塞主线程
Pickle load on off thread blocks main thread
调用 ObClass
的 prep()
会阻塞主线程,直到 pickle 完成。为什么?如何在后台取消数据?
在家试试这个:
def PrepFn(ob):
ob.lock.acquire(1)
try:
print "begin load"
f = open(ob.filename, "rb")
ob.data = cPickle.load(f)
print "end load"
except Exception as msg:
print(str(msg))
ob.lock.release()
f.close()
class ObClass:
def __init__(self, filename):
self.lock = threading.Lock()
self.filename = filename
self.data = None
def prep(self):
thread.start_new_thread(PrepFn, (self,))
def get(self):
self.lock.acquire(1)
self.lock.release()
return self.data
def make_data(filename):
print "generating data"
data = np.asarray(np.random.normal(size=(10000, 1000)))
print "writing data to disk"
f = open(filename, "wb")
cPickle.dump(data, f)
f.close()
def test(filename):
x = ObClass(filename)
x.prep()
for i in xrange(1000):
print i
print "get data"
data = x.get()
print "got data"
要查看实际效果,请执行
filename = "test.pkl"
test.make_data(filename)
test.test(filename)
对我来说,是这样的:
0
1
2
begin load
3
4
[...]
83
接着是长时间的停顿,接着是
end load
84
85
86
[...]
996
997
998
999
get data
got data
Python 具有全局解释器锁 (GIL),这意味着解释器在一个进程中所做的一切都必须限制在一个 CPU 核心中。
当您启动 IO 线程时,它正在被调度但不会立即启动。因此延迟。
当您的线程启动时,它会触发 IO 中断。 IO 由外部 C 例程完成,因此您的 IO 线程可以释放 GIL。然后,这使您的主线程能够 运行 并继续打印直到 83.
然后你的 IO 调用来自 C 例程 returns 数据流,它被你的 Python IO 线程捕获。当Python IO 线程运行s 解析数据流为Python 对象时,您的主线程需要等待,这会导致暂停。 (cPickle
通常需要双倍RAM来展开对象,所以如果你监控top
,你可以看到对象展开的实时执行)
当你的IO线程完成解析数据后,你的主线程再次启动打印到最后并调用get。
调用 ObClass
的 prep()
会阻塞主线程,直到 pickle 完成。为什么?如何在后台取消数据?
在家试试这个:
def PrepFn(ob):
ob.lock.acquire(1)
try:
print "begin load"
f = open(ob.filename, "rb")
ob.data = cPickle.load(f)
print "end load"
except Exception as msg:
print(str(msg))
ob.lock.release()
f.close()
class ObClass:
def __init__(self, filename):
self.lock = threading.Lock()
self.filename = filename
self.data = None
def prep(self):
thread.start_new_thread(PrepFn, (self,))
def get(self):
self.lock.acquire(1)
self.lock.release()
return self.data
def make_data(filename):
print "generating data"
data = np.asarray(np.random.normal(size=(10000, 1000)))
print "writing data to disk"
f = open(filename, "wb")
cPickle.dump(data, f)
f.close()
def test(filename):
x = ObClass(filename)
x.prep()
for i in xrange(1000):
print i
print "get data"
data = x.get()
print "got data"
要查看实际效果,请执行
filename = "test.pkl"
test.make_data(filename)
test.test(filename)
对我来说,是这样的:
0
1
2
begin load
3
4
[...]
83
接着是长时间的停顿,接着是
end load
84
85
86
[...]
996
997
998
999
get data
got data
Python 具有全局解释器锁 (GIL),这意味着解释器在一个进程中所做的一切都必须限制在一个 CPU 核心中。
当您启动 IO 线程时,它正在被调度但不会立即启动。因此延迟。
当您的线程启动时,它会触发 IO 中断。 IO 由外部 C 例程完成,因此您的 IO 线程可以释放 GIL。然后,这使您的主线程能够 运行 并继续打印直到 83.
然后你的 IO 调用来自 C 例程 returns 数据流,它被你的 Python IO 线程捕获。当Python IO 线程运行s 解析数据流为Python 对象时,您的主线程需要等待,这会导致暂停。 (cPickle
通常需要双倍RAM来展开对象,所以如果你监控top
,你可以看到对象展开的实时执行)
当你的IO线程完成解析数据后,你的主线程再次启动打印到最后并调用get。