Python中的不变性和线程安全性

我正在清理我写的一些Python代码,当时我不是那么知识渊博.主要是我正在消除由于对Python中的线程不完全理解而产生的一些复杂性.我需要创建一个线程安全的项目列表,我想通过不可变列表,而不是通常的锁定方法.我知道不可变对象在线程方面非常特殊,因为围绕不完整状态更改的所有线程安全问题都会消失.

所以,我问:以下代码是否是线程安全的?

class ImmutableList(object):
    def __init__(self):
        self._list = ()

    def __iter__(self):
        return self._list.__iter__()

    def append(self, x):
        self._list = self._list + tuple([x])

我认为是,因为每次都会构建一个新列表.如果在另一个线程迭代它时更新列表,则旧列表将继续用于迭代的剩余部分.这对我来说很好,但可能不适合所有人.

这也是个好主意吗?我只想将其应用于列表大小较小的几种情况,并且列表不会发生太大变化(事件监听器会浮现在脑海中).

最佳答案
首先,在Python编程语言的CPython参考实现中,附加到列表已经是线程安全的.换句话说,虽然语言规范不要求列表类是线程安全的,但无论如何.因此,除非您使用Jython或IronPython或其他类似的Python实现,否则您没问题.

其次,您还需要重载其他列表操作,例如__setitem__和__setslice__等.我假设您的实现处理此问题.

最后,你的问题的答案是否定的:你的代码不是线程安全的.考虑以下情况:

>您的清单包含(5,6)
>线程1尝试追加7,线程2尝试追加8
>线程1构造另一个元组(5,6,7),在此之前可以分配给_list,有一个上下文切换
>线程2执行其赋值,因此列表现在是(5,6,8)
>线程1控制CPU返回并分配给_list,覆盖先前的追加.该列表现在是(5,6,7),8已经丢失.

这个故事的寓意是你应该使用锁定并避免聪明.

转载注明原文:Python中的不变性和线程安全性 - 代码日志