如果只有一个编写器将字节附加到bytearray
,并且有多个读取器从中读取数据,那么一个或多个读者是否有可能读取既不是在延伸之后又没有读取的数据?
例如,如果bytearray
中的旧数据是0123
,那么作者用4567
扩展,新数据将是01234567
。是否有可能(因为竞争条件)在延长期间读取012345
或0123abcd
等数据?
编辑。作者将调用.extend(data)
或使用+= data
将数据添加到bytearray
。 data
是bytes
或另一个bytearray
对象。
如果你只能保证一个编写器,那么它取决于你传递给bytearray.extend()
方法或+=
语句的可迭代类型,如果这将是原子的。
Python线程在字节码之间切换,并且调用bytearray.extend()
或将+=
语句应用于bytearray
对象是单字节码,前提是迭代不需要字节码执行。如果传入的对象是在Python中实现的可迭代,那么所有的注意都会关闭,因为这需要执行多个字节码解释步骤。
例如:
to_extend = (int(v) for v in '0123456789')
shared_bytearray_reference += to_extend # not atomic, readers can see between 0 and 10 bytes appended
不会是原子的,因为生成器表达式循环是用Python实现的。
但是从list
对象扩展将是原子的,因为内置类型(如列表)的迭代是在本机代码中实现的:
to_extend = [int(v) for v in '0123456789']
shared_bytearray_reference += to_extend # atomic, readers will see 10 bytes appended
同样,如果您使用带有Python函数的map()
迭代器:
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类型上运行的代码。
总而言之,如果有疑问,最好使用一个锁而不用担心你正在迭代的对象是原生的。