更新传递到python线程中的变量
我目前在理解线程方面遇到了一些问题,或者可能在理解python中如何通过线程传递/分配变量方面遇到了一些问题。我有一个简单的程序,它接收屏幕上显示的当前股票列表,并获取与这些股票相关的股票信息。我使用线程,这样我可以不断更新屏幕,不断收集数据。我有两个问题:更新传递到python线程中的变量,python,python-3.x,multithreading,python-multithreading,Python,Python 3.x,Multithreading,Python Multithreading,我目前在理解线程方面遇到了一些问题,或者可能在理解python中如何通过线程传递/分配变量方面遇到了一些问题。我有一个简单的程序,它接收屏幕上显示的当前股票列表,并获取与这些股票相关的股票信息。我使用线程,这样我可以不断更新屏幕,不断收集数据。我有两个问题: 在dataCollector_-thread()内部,我知道如果我将stocksOnScreenListInfo附加到main中,那么main中的变量(stocksOnScreenListInfo)将被更新 但是,我不想附加到列表中,而只是
dataCollector_-thread()
内部,我知道如果我将stocksOnScreenListInfo
附加到main
中,那么main中的变量(stocksOnScreenListInfo
)将被更新
def dataCollector_thread(stocksOnScreenListInfo, stocksOnScreen):
while(True):
placeholder = []
for stock in stocksOnScreen:
placeholer.append(RetrieveQuote(stock))
stocksOnScreenListInfo = placeholder
time.sleep(5)
screenUpdate\u线程中
我想将stocksOnScreen
更新为函数UpdateScreen
定义的变量“TSLA”。这似乎并没有更新其在main
中对应的stocksOnScreen
,因为当我打印检查时,它继续说“AAPL”
def main(args):
stocksOnScreen = ["AAPL"] # List of the stocks currently displayed on LED screen
stocksOnScreenListInfo = [] # The quote information list for each stock on screen
thread_data_collector = threading.Thread(target=dataCollector_thread, args=(stocksOnScreenListInfo,stocksOnScreen))
thread_data_collector.daemon = True
thread_data_collector.start()
thread_screen = threading.Thread(target=screenUpdate_thread, args=(stocksSearchArray,stocksOnScreen))
thread_screen.daemon = True
thread_screen.start()
def dataCollector_thread(stocksOnScreenListInfo, stocksOnScreen):
while(True):
for stock in stocksOnScreen:
stocksOnScreenListInfo.append(RetrieveQuote(stock))
time.sleep(5)
def screenUpdate_thread(stocksSearchArray, stocksOnScreen):
while(True):
stocksOnScreen = UpdateScreen(stocksSearchArray)
def UpdateScreen(stocksSearchArray):
pass
return ["TSLA"]
stocksOnScreen=…
更改引用本身。由于引用作为参数传递给函数/线程,因此会对函数/线程中原始引用的副本进行更改。(两个函数/线程都有自己的副本。)
因此,您应该操作它所引用的列表对象(例如list.clear()
和list.extend()
)
然而,正如你所看到的,它现在不再是一个原子行为。因此,dataCollector\u thread
可能会在一个空列表上工作(即什么都不做)并睡眠5秒钟。我也在下面提供了一个可能的解决方法。但不确定它是否应该(完美地)工作:
注意:根据,python列表是线程安全的,因此复制解决方案应该可以工作
您可能还可以使用而不是将
stocksOnScreen
作为参数传递:
def dataCollector_thread():
global stocksOnScreen # superfluous if no re-assignment
while(True):
for stock in stocksOnScreen:
print(stock)
time.sleep(5)
def UpdateScreen():
return ["TSLA"]
def screenUpdate_thread():
global stocksOnScreen # needed for re-assignment
while(True):
stocksOnScreen = UpdateScreen()
def main():
global stocksOnScreen # Or create stocksOnScreen outside main(), which is a function itself
stocksOnScreen = ["AAPL"] # List of the stocks currently displayed on LED screen
thread_data_collector = threading.Thread(target=dataCollector_thread)
thread_data_collector.daemon = True
thread_data_collector.start()
thread_screen = threading.Thread(target=screenUpdate_thread)
thread_screen.daemon = True
thread_screen.start()
参考:此功能有几个问题:
- 您正在将此函数中的
分配给一个新的列表stocksOnScreenListInfo
。您要做的是修改内容,以便更新占位符
中的main
。您可以这样做:stocksOnScreenListInfo
(这意味着使用新列表从头到尾更改内容)stocksOnScreenListInfo[:]=placeholder
在for循环中迭代时可能会更改,因为您正在另一个线程中更新它。你应该原子化地做这件事。A. (您将其作为参数传递给函数)将在这里有所帮助:它是一个同步原语,设计用于在多个线程共享数据且其中至少一个线程修改数据时防止数据争用stocksOnScreen
stocksOnScreenListInfo
在您的代码中的任何其他地方使用。它是否用于其他功能?如果是这样的话,你应该考虑在它周围加一把锁
我将对函数进行如下修改:
def dataCollector_thread(stocksOnScreenListInfo, stocksOnScreen, lock):
while True:
placeholder = []
with lock: # use lock to ensure you atomically access stocksOnScreen
for stock in stocksOnScreen:
placeholder.append(RetrieveQuote(stock))
stocksOnScreenListInfo[:] = placeholder # modify contents of stocksOnScreenListInfo
time.sleep(5)
在其他线程函数中:
您正在将stocksOnScreen
分配给此函数中的新列表;它不会影响main
中的stocksOnScreen
。同样,您可以使用符号stocksOnScreen[:]=new_list
来完成此操作。在更新stocksOnScreen
之前,我会锁定,以确保您的其他线程函数dataCollector\u thread
以原子方式访问stocksOnScreen
:
def screenUpdate_thread(stocksSearchArray, stocksOnScreen, lock):
while True:
updated_list = UpdateScreen() # build new list - doesn't have to be atomic
with lock:
stocksOnScreen[:] = updated_list # update contents of stocksOnScreen
time.sleep(0.001)
正如你所看到的,我在一个小睡眠,否则的功能将不断循环,太CPU密集。另外,它将为Python提供一个在线程函数之间切换上下文的机会
最后,在main
中创建一个锁:
lock = threading.Lock()
并将
lock
作为参数传递给这两个函数。这里有三个选项,因为类似python的java是通过值而不是引用传递参数的
def threadFunction():
globalParam = "I've ran"
global globalParam
threading.Thread(target=threadFunction)
首先,使用全局参数
def threadFunction():
globalParam = "I've ran"
global globalParam
threading.Thread(target=threadFunction)
第二,更新程序函数
def threadFunction(update):
update("I've ran")
threading.Thread(target=threadFunction, args=((lambda x: print(x)),))
第三,公开全局参数持有者
def threadFunction(param1, param2):
globalParams[0]= param1 + " Just Got access"
global globalParams
globalParams = ["Param1","Param2"]
threading.Thread(target=threadFunction, args=(*globalParams))
我希望这回答了你的问题;) 我想知道,如果使用
list[:]=
方法(换句话说,它是否会被另一个线程中的迭代所阻止?)@TomYan没有这样的保证。尽管Python有一个全局解释器锁,但当一个线程迭代一个列表,而另一个线程变异同一个列表时,仍然存在潜在的争用条件。最好使用锁来防止它。我只是想知道python列表是线程安全的确切定义是什么。。。
def threadFunction(update):
update("I've ran")
threading.Thread(target=threadFunction, args=((lambda x: print(x)),))
def threadFunction(param1, param2):
globalParams[0]= param1 + " Just Got access"
global globalParams
globalParams = ["Param1","Param2"]
threading.Thread(target=threadFunction, args=(*globalParams))