我正在处理一个线程python程序。一个线程在列表上迭代(通过调用iterate
)。另一个线程可能(很少)尝试使用remove_element
从同一列表中删除元素:
my_list = [ large number of elements ]
def iterate():
for item in my_list:
yield item
def remove_element(x):
my_list.remove(x)
我不想为迭代使用锁,因为迭代可能需要相当长的时间,而且我不想阻止编写器超过绝对必要的时间。
我担心如果作者在错误的时刻出现,我会在迭代线程中“丢失”元素:例如。如果迭代线程在元素1处,并且我删除元素0,则元素1变为新元素0并且迭代线程将“跳过”该元素。
问题1 :这是实际发生的事情,还是Python比那更聪明?
假设我是对的,我正在寻找解决方案。由于各种原因,我不想要在迭代开始之前复制列表(它非常大,我需要尽可能多地保存内存)。所以我想到了以下解决方案:
当我在迭代时,我正在设置一个迭代正在进行的标志。如果删除线程注意到它,它不会立即删除该元素,而是将其添加到to_be_removed
列表中以便以后删除。
在迭代线程中完成迭代后,它会检查to_be_removed
中是否有元素并将其删除。
my_list = [ large number of elements ]
to_be_removed = []
iterating = False
lock = Threading.Lock()
def iterate():
with lock:
iterating = True
try:
for item in my_list:
yield item
finally:
with lock:
iterating = False
while to_be_removed:
my_list.remove(to_be_removed.pop())
def remove_element(x):
with lock:
if iterating:
to_be_removed.append(x)
else:
my_list.remove(x)
问题2 :这是一个可靠的解决方案吗?是否有一个更简单的解决方案,不涉及创建要迭代的列表副本,并且在迭代期间不会阻止编写器?是否有可能提供我需要的标准库类?