Executor Map 没有 运行 函数
Executor Map doesn't run a function
我正在尝试重现竞争条件。下面的代码在使用 submit 而不是 map 时工作正常,但我想了解为什么 map 没有 运行 更新方法。
import concurrent.futures
import time
class BankAccount:
def __init__(self):
self.balance = 100 # shared data
def update(self, transaction, amount):
print(f'{transaction} started')
tmp_amount = self.balance # reading from db
tmp_amount += amount
time.sleep(1)
self.balance = tmp_amount
print(f'{transaction} ended')
if __name__ == '__main__':
acc = BankAccount()
print(f'Main started. acc.Balance={acc.balance}')
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as ex:
ex.map(acc.update, [dict(transaction='refill', amount=100),
dict(transaction='withdraw', amount=-200)])
print(f'End of Main. Balance={acc.balance}')
在单独的可迭代对象中传递每种参数。
ex.map(acc.update, ['refill', 'withdraw'], [100, -200])
像map
一样,Executor.map
每个参数接受一个可迭代对象,并将每个可迭代对象的分配给一个争论。此外,在实际访问结果之前不会传播错误。
Executor.map(func, *iterables, timeout=None, chunksize=1)
Similar to map(func, *iterables)
...
If a func call raises an exception, then that exception will be raised when its value is retrieved from the iterator.
因此,代码错误地传递了参数,但抑制了错误。获取值,例如通过 list(ex.map(...))
显示错误:
TypeError: update() missing 1 required positional argument: 'amount'
为每种参数创建一个单独的迭代器可以防止这种情况。
# V transaction
ex.map(acc.update, ['refill', 'withdraw'], [100, -200])
# ^ amount
可能需要通过调用而不是种类来排序参数。使用 zip
和 *
解包将输入转换为 map
所要求的。
ex.map(acc.update, *zip(('refill', 100), ('withdraw', 200)))
如果需要关键字参数,则需要帮助程序来解压参数。
def kwargify(func):
"""Wrap ``func`` to accept a dictionary of keyword arguments"""
return lambda kwargs: func(**kwargs)
传递给 ex.map
时,只需用这个助手包装所需的函数即可:
ex.map(
kwargify(acc.update),
[
dict(transaction='refill', amount=100),
dict(transaction='withdraw', amount=-200)
]
)
我正在尝试重现竞争条件。下面的代码在使用 submit 而不是 map 时工作正常,但我想了解为什么 map 没有 运行 更新方法。
import concurrent.futures
import time
class BankAccount:
def __init__(self):
self.balance = 100 # shared data
def update(self, transaction, amount):
print(f'{transaction} started')
tmp_amount = self.balance # reading from db
tmp_amount += amount
time.sleep(1)
self.balance = tmp_amount
print(f'{transaction} ended')
if __name__ == '__main__':
acc = BankAccount()
print(f'Main started. acc.Balance={acc.balance}')
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as ex:
ex.map(acc.update, [dict(transaction='refill', amount=100),
dict(transaction='withdraw', amount=-200)])
print(f'End of Main. Balance={acc.balance}')
在单独的可迭代对象中传递每种参数。
ex.map(acc.update, ['refill', 'withdraw'], [100, -200])
像map
一样,Executor.map
每个参数接受一个可迭代对象,并将每个可迭代对象的分配给一个争论。此外,在实际访问结果之前不会传播错误。
Executor.map(func, *iterables, timeout=None, chunksize=1)
Similar to
map(func, *iterables)
...If a func call raises an exception, then that exception will be raised when its value is retrieved from the iterator.
因此,代码错误地传递了参数,但抑制了错误。获取值,例如通过 list(ex.map(...))
显示错误:
TypeError: update() missing 1 required positional argument: 'amount'
为每种参数创建一个单独的迭代器可以防止这种情况。
# V transaction
ex.map(acc.update, ['refill', 'withdraw'], [100, -200])
# ^ amount
可能需要通过调用而不是种类来排序参数。使用 zip
和 *
解包将输入转换为 map
所要求的。
ex.map(acc.update, *zip(('refill', 100), ('withdraw', 200)))
如果需要关键字参数,则需要帮助程序来解压参数。
def kwargify(func):
"""Wrap ``func`` to accept a dictionary of keyword arguments"""
return lambda kwargs: func(**kwargs)
传递给 ex.map
时,只需用这个助手包装所需的函数即可:
ex.map(
kwargify(acc.update),
[
dict(transaction='refill', amount=100),
dict(transaction='withdraw', amount=-200)
]
)