我的问题
我一直在使用Python库Thread,它在返回正确结果方面似乎存在一些问题。当我运行相同的功能时,例如连续十次,八次结果正确,两次错误。
当结果错误时,这是因为来自各个调用的一些结果字典似乎被随机合并在一起。
我的代码:
此函数创建一个 session ,重试某些状态代码的其余调用:
# Makes retry sessions
def requests_retry_session(retries=3,backoff_factor=0.3,status_forcelist=(500, 502, 504),session=None):
"""
Description:
Creates a session which uses retries
Input:
retries (int): Max number of retries
backoff_factor (int): Time between retries
status_forcelist (tuble): Status for which to retry
Returns:
session: Requests session which handles different status and connection errors
"""
session = session or requests.Session()
retry = Retry(
total=retries,
read=retries,
connect=retries,
redirect=retries,
backoff_factor=backoff_factor,
status_forcelist=status_forcelist,
)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session
此函数对多个 url 进行剩余调用:
def make_rest_calls(urls, header, store=None):
"""
Description:
Processes list of urls
Input:
urls (list): List of urls for rest call
header (dictionary): Dictionary containing credentials
store (dictionary): Dictionary for collecting results
Returns:
store (dictionary): Dictionary with results
"""
if store is None:
store = {}
for url in urls:
store[url] = requests_retry_session().get(url, headers=header, timeout=5)
return store
该函数以多线程方式运行剩余调用
def run_multi_threaded(nthreads, list_of_urls, header):
"""
Description:
Runs multiple threads
Input:
nthreads (int): Number for threads to run
list_of_urls(list): List of rest urls
header (dictionary): Dictionary containing credentials
Returns:
store (dictionary): Dictionary with results
"""
store = {}
threads = []
# create the threads
for i in range(nthreads):
small_list_of_urls = list_of_urls[i::nthreads]
t = Thread(target=make_rest_calls, args=(small_list_of_urls))
threads.append(t)
# start the threads
[t.start() for t in threads ]
# wait for the threads to finish
[ t.join() for t in threads ]
return store
问题
这是该软件包的弱点吗?我应该使用多个进程吗?或者我做错了什么,只在某些时候导致这种副作用?
我需要进行很多调用,因此需要多线程完成。显然也必须是正确的。
最佳答案
正如 blhsing 提到的,这个问题可能没有显示一些有助于回答它的细节。
根据结果的描述(随机合并输出,仅在某些情况下),似乎在以下情况下可能会发生并发问题:
- 您确实将 store 作为参数传递给线程启动中的 make_rest_calls 函数。 (如果 make_rest_calls 中 store 的默认值确实是“{}”而不是 None,也可能会发生这种情况)
- list_of_urls 中几乎没有重复项。
如果这两种情况以某种方式发生,结果可能如所描述的那样,因为两个不同的线程可能会尝试同时更改同一存储条目。
如果是这种情况,简单的解决方案可能是确保您的 list_of_urls 不会两次保存相同的 URL。 (例如,您可能想使用 set(list_of_urls)。)
值得一提的是,至少在这种用法中,make_rest_calls 函数中没有返回任何内容,因为线程不返回函数的返回值。例如,唯一可行的方法是改变输入存储值,而不是返回任何内容。
关于Python 线程随机返回错误结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56579256/