Python 对于一个写入程序和多个读取程序,`bytearray`线程安全吗?
如果只有一个写入程序将字节追加到Python 对于一个写入程序和多个读取程序,`bytearray`线程安全吗?,python,arrays,python-3.x,Python,Arrays,Python 3.x,如果只有一个写入程序将字节追加到字节数组,并且有多个读卡器从中读取,那么一个或多个读卡器是否有可能读取扩展之前或之后都不存在的数据 例如,如果bytearray中的旧数据是0123,则写入程序扩展为4567,新数据将是01234567。任何读卡器是否可以(由于竞争条件)在扩展期间读取数据,如012345或0123abcd 编辑。编写器将调用.extend(data)或使用+=data将数据添加到字节数组中。数据是一个字节或另一个bytearray对象。如果您可以保证只有一个写入程序,那么它取决于
字节数组
,并且有多个读卡器从中读取,那么一个或多个读卡器是否有可能读取扩展之前或之后都不存在的数据
例如,如果bytearray
中的旧数据是0123
,则写入程序扩展为4567
,新数据将是01234567
。任何读卡器是否可以(由于竞争条件)在扩展期间读取数据,如012345
或0123abcd
编辑。编写器将调用
.extend(data)
或使用+=data
将数据添加到字节数组中。数据
是一个字节
或另一个bytearray
对象。如果您可以保证只有一个写入程序,那么它取决于您传递给bytearray.extend()
方法的iterable类型,或者+=
语句(如果它是原子的话)
Python线程“在字节码之间”切换,并调用bytearray.extend()
或将+=
语句应用于bytearray
对象是单个字节码,前提是迭代不需要执行字节码。如果传入的对象是用Python实现的iterable,那么所有赌注都是无效的,因为这需要执行多个字节码解释步骤
例如:
不会是原子的,因为生成器表达式循环是用Python实现的
但是从列表扩展对象将是原子的,因为对内置类型(如列表)的迭代是在本机代码中实现的:
to_extend = [int(v) for v in '0123456789']
shared_bytearray_reference += to_extend # atomic, readers will see 10 bytes appended
类似地,如果将map()
迭代器与Python函数一起使用:
to_extend = map(lambda v: int(v), '0123456789')`
shared_bytearray_reference += to_extend # not atomic, readers can see between 0 and 10 bytes appended
这不是原子性的,因为每个迭代步骤都调用Python函数,并且每次都执行字节码
但是传入一个本机函数,如int
:
to_extend = map(int, '0123456789') # int is a built-in native function
shared_bytearray_reference += to_extend # atomic, readers will see 10 bytes appended
然后一切都可以在一个字节码解释步骤中执行
一些本机代码将解锁全局解释器锁,允许其他Python线程在本机代码独立运行时执行,但这几乎不涉及在Python类型上运行的代码
总而言之,当有疑问时,最好使用锁,不要担心您迭代的对象是否是本地对象 请显示如何追加这些字节。问题不在于附加,而在于您使用什么代码来完成它。@MartijnPieters编辑。它实际上是最简单的用例之一,使用.extend()
或+=
。好的,下面的答案适用。如果数据
是内置序列类型或应用内置函数的映射()
,则它是原子的,否则就不是。@MartijnPieters我的案例只涉及字节
和字节数组
。从你的回答来看,我想我现在可以保持这样。但是我想知道我们可以依赖bytes
或bytearray
上的迭代是本机的这一事实多久?这符合规格吗?对于这个用例,您会推荐一个锁还是另一个线程安全的容器?没有规范,我建议在有疑问时锁定。
to_extend = map(int, '0123456789') # int is a built-in native function
shared_bytearray_reference += to_extend # atomic, readers will see 10 bytes appended