如何避免这里的比赛条件

2024-05-16 03:14:51 发布

您现在位置:Python中文网/ 问答频道 /正文

如果我使用线程运行这个程序,getUrl中会有竞争条件吗?我正在多个线程中更改data['key']的值。我需要将整个data传递给我发出的请求,基本上,一组键是固定的,对于我发出的每个线程调用,只有名为key的键会改变

import requests
from concurrent.futures import ThreadPoolExecutor


def getUrl(url, value):
    data['key'] = value # will there be a race condition here
    return requests.get(url, data=data).text # and when the value is passed here

data = {'key': 1, 'fixedKey': 'fixedValue', 'fixedKey2': 'fixedValue2'}
resultArray = []
threadPool = ThreadPoolExecutor(32)

for i in range(100):
    resultArray.append(threadPool.submit(getUrl, 'https://google.com', i))

Thread Safety in Python's dictionary我检查了这个,但我的困惑是,当我在data['key'] = value中进行设置时,线程是否会切换上下文,然后其他一些线程会进行更改,而下一行现在有一个不同线程设置的新值

范例

Value set by thread 1
data['key'] = 1
Context Switch
Value set by thread 2
data['key'] = 2
Context Switch back to old thread 1
is data['key'] = `2` now? I would necessarily want the value `1`

如果我使用锁,那么我将失去这里的并发性


Tags: thekeyimporturldatahereisvalue
2条回答

存在竞态条件,因为data在线程之间共享,您可以从线程中对其进行变异

可视化此竞争条件的一种简单方法是使用sleepprint模拟request调用:

from concurrent.futures import ThreadPoolExecutor
from time import sleep

def getUrl(url, value):
    data['key'] = value
    sleep(0.3)
    print(value, data["key"])

data = {'key': 1, 'fixedKey': 'fixedValue', 'fixedKey2': 'fixedValue2'}
resultArray = []
threadPool = ThreadPoolExecutor(32)

for i in range(100):
    resultArray.append(threadPool.submit(getUrl, 'https://google.com', i))

您将看到传递给getUrl的值有时与存储在data中的值不同

一种解决方法是在变异前将data复制到局部

您当前的代码确实存在竞争条件,因为您正在不同的线程中更改并使用相同的全局变量。一种简单的方法是使用本地副本:

def getUrl(url, value):
    data2 = dict(data, 'key' = value)         # build a local instance
    return requests.get(url, data=data2).text # and use it: no race condition

相关问题 更多 >