<p>当GIL出现问题时,解决方法是将任务细分为块,这样可以刷新块之间的GUI。在</p>
<p>例如,假设您有一个大的S大小的列表要转储,那么您可以尝试定义一个从list派生并重写getstate的类来返回N个子pickle对象,每个对象都是一个类的实例,比如subpicle,包含列表中的S/N项。每个子块仅在酸洗时存在,并定义getstate执行两个操作:</p>
<ul>
<li>呼叫qApp.processEvents()在gui上,以及</li>
<li>返回序列号项目的子列表。在</li>
</ul>
<p>在取消拾取时,每个子项都将刷新GUI并获取项列表;最后,在原始对象中从其setstate中接收的所有子项中重新创建总列表。在</p>
<p>如果您想在控制台应用程序(或非pyqt gui)中取消pickle,您应该抽象出对process事件的调用。为此,可以在子菜单上定义一个类范围的属性,比如process_events,默认情况下为None;如果不是None,setstate会将其作为函数调用。因此,默认情况下,子点击之间没有GUI刷新,除非取消拾取的应用程序在开始取消拾取之前将此属性设置为可调用。在</p>
<p>这种策略将使您的GUi在取消拾取过程中有机会重新绘制(如果需要,只使用一个线程)。在</p>
<p>实施取决于您的确切数据,但下面是一个示例,它演示了一个大列表的原理:</p>
<pre><code>import pickle
class SubList:
on_pickling = None
def __init__(self, sublist):
print('SubList', sublist)
self.data = sublist
def __getstate__(self):
if SubList.on_pickling is not None:
print('SubList pickle state fetch: calling sub callback')
SubList.on_pickling()
return self.data
def __setstate__(self, obj):
if SubList.on_pickling is not None:
print('SubList pickle state restore: calling sub callback')
SubList.on_pickling()
self.data = obj
class ListSubPickler:
def __init__(self, data: list):
self.data = data
def __getstate__(self):
print('creating SubLists for pickling long list')
num_chunks = 10
span = int(len(self.data) / num_chunks)
SubLists = [SubList(self.data[i:(i + span)]) for i in range(0, len(self.data), span)]
return SubLists
def __setstate__(self, subpickles):
self.data = []
print('restoring Pickleable(list)')
for subpickle in subpickles:
self.data.extend(subpickle.data)
print('final', self.data)
def refresh():
# do something: refresh GUI (for example, qApp.processEvents() for Qt), show progress, etc
print('refreshed')
data = list(range(100)) # your large data object
list_pickler = ListSubPickler(data)
SubList.on_pickling = refresh
print('\ndumping pickle of', list_pickler)
pickled = pickle.dumps(list_pickler)
print('\nloading from pickle')
new_list_pickler = pickle.loads(pickled)
assert new_list_pickler.data == data
print('\nloading from pickle, without on_pickling')
SubList.on_pickling = None
new_list_pickler = pickle.loads(pickled)
assert new_list_pickler.data == data
</code></pre>
<p>易于应用于dict,甚至可以使用isinstance使其适应它接收的数据类型。在</p>