【发布时间】:2013-11-13 19:25:54
【问题描述】:
我想通过启动多个独立的异步操作线程来加速脚本的执行,否则这些线程会一个接一个地启动。
我使用了the example from concurrent.future docs 并将其改编为我的代码:
import concurrent.futures
def myfunc(elem):
elem['ascii'] = ord(elem['name'])
mylist = [
{'name': 'a'},
{'name': 'b'},
{'name': 'c'},
{'name': 'd'},
{'name': 'e'}
]
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
future_to_url = {executor.submit(myfunc, elem): elem for elem in mylist}
for future in concurrent.futures.as_completed(future_to_url):
try:
future.result()
except Exception as exc:
print('error: '.format(exc))
print mylist
代码按预期工作,但我是否应该担心对mylist 的并发访问,或者是否正确锁定并以串行方式访问(或任何正确的方式以使数据保持一致)?
在实际程序中,字典会大得多,我想启动约 500 名工人。
【问题讨论】:
-
您的示例中的多个线程不使用列表和字典:列表仅由主线程访问,每个线程都使用自己的字典。
-
是的,每个线程都将使用列表
mylist中的自己的字典。我担心的是,当修改字典时,列表也会间接更新,可能同时由多个线程(除非它被实现为某种指向字典的指针列表,在这种情况下它不会改变) -
为什么改变一个恰好是列表中的项目的对象会以任何方式影响列表?例如,您可以使用元组(不可变对象)而不是列表,它不会破坏您的示例
-
@J.F. Sebastian:我不知道,这就是我问这个问题的原因。我可以想象一个实现,其中列表及其内容是内存中的一大块(而不是指针列表(在 C 语义中)),并且其中一个组件的任何更改都会更改整个列表,这可能会在并发中产生问题使用权。很高兴知道 Python 在内部和外部一样出色 :)
-
此行为不依赖于实现。一切都是 Python 中的对象(无论是 CPython、Pypy、IronPython、Jython),因此需要“引用”语义。有些容器可以将它们的项目作为普通 C 类型存储在“内存中的一大块”中——
bytearray、array.array、numpy数组并在访问时创建相应的 Python 对象。它仍然不会改变语义,因为相应的 Python 对象是不可变的(int、float、bytes)。
标签: python multithreading dictionary concurrency