剥离螺纹加载主螺纹

时间:2015-11-19 06:03:49

标签: multithreading pickle

调用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

1 个答案:

答案 0 :(得分:1)

Python具有全局解释器锁(GIL),这意味着解释器在一个进程中完成的所有操作都必须限制在一个CPU核心中。

启动IO线程时,它正在调度但不会立即启动。因此延迟。

当线程启动时,它会触发IO中断。 IO由外部C例程完成,因此您的IO线程可以释放GIL。然后,这将使您的主线程运行并保持打印直到83。

然后,来自C例程的IO调用将返回数据流,该数据流由Python IO线程捕获。当Python IO线程运行并将数据流解析为Python对象时,主线程需要等待,这会导致暂停。 (cPickle通常需要双RAM来展开对象,所以如果你监视top,你可以看到对象展开的实时执行情况。

当您的IO线程完成解析数据时,您的主线程再次开始打印到结尾并调用get。