Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.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
Multithreading 非线程上的酸洗负载阻塞主线程_Multithreading_Pickle - Fatal编程技术网

Multithreading 非线程上的酸洗负载阻塞主线程

Multithreading 非线程上的酸洗负载阻塞主线程,multithreading,pickle,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

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

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


当IO线程完成数据解析后,主线程将再次开始打印到末尾并调用get。

是否在启动后调用wait\u new\u thread?还是你想再锁一次?没有。没有呼叫等待,而且我直到很久以后才碰锁。请您再粘贴一些代码好吗?我制作了一个完整的示例,您可以运行。谢谢,这很有意义。但我不知道如何避开这个问题——或者我能吗?不可能在后台线程上取消勾选吗?Python社区的一个官方建议是使用多处理而不是线程。也就是说,如果您的进程严重受限于IO,线程仍然是可行的。一般建议将数据分成两部分。你为什么需要pickle而不是文本?在Python中,线程的工作方式通常是IO->text deserialize+compute->IO。而是执行IO+cPickle反序列化->计算->IO+cPickle反序列化。像json这样的文本序列化也可以很快(使用ujson)。我的对象很大,我找不到在进程之间的共享内存中进行酸洗的方法。最终,我必须以某种方式将数据传输到另一个进程,我怀疑这需要序列化/反序列化,这可能意味着节省的时间很少。我不确定你所说的关于订购的最后一部分是什么意思。在一个CPU内核中执行线程时,你希望至少有一个线程在执行过程中始终释放GIL。性能增益是基于实现这一点的精心设计。这就是为什么即使使用GIL,IO绑定作业也能从线程中获益,因为IO主要由外部例程和内核设备完成。这意味着您希望启动主要执行IO的线程,而让计算线程去反序列化数据并执行有意义的计算。文件上的cPickle.load不是纯粹的IO,它是IO+严重的反序列化。这里有一种方法可以工作:将pickle拆分为两个pickle,让IO线程将文件读取到从内存中的IO.ByteIO创建的文件对象中。让您的计算线程加载ByteIO文件。这将启用纯IO线程和纯计算线程。除了打印测试输出外,还需要两个pickle来提高有用计算的性能