更新传递到python线程中的变量

2024-10-02 08:20:24 发布

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

我目前在理解线程方面遇到了一些问题,或者可能在理解python中如何通过线程传递/分配变量方面遇到了一些问题。我有一个简单的程序,它接收屏幕上显示的当前股票列表,并获取与这些股票相关的股票信息。我使用线程,这样我可以不断更新屏幕,不断收集数据。我有两个问题:

  1. dataCollector_thread()内部,我理解如果我在stocksOnScreenListInfo中追加变量(stocksOnScreenListInfo),那么main内部的变量(stocksOnScreenListInfo)将被更新

但是,我不想附加到列表中,而只是像下面那样重新分配列表,但这不起作用

def dataCollector_thread(stocksOnScreenListInfo, stocksOnScreen):
    while(True):
        placeholder = []
        for stock in stocksOnScreen:
            placeholer.append(RetrieveQuote(stock))
        stocksOnScreenListInfo = placeholder
        time.sleep(5)
  1. screenUpdate_thread内,我想将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"]
    

Tags: true列表formaindefstock线程screen
3条回答

此功能有几个问题:

def dataCollector_thread(stocksOnScreenListInfo, stocksOnScreen):
    while(True):
        placeholder = []
        for stock in stocksOnScreen:
            placeholer.append(RetrieveQuote(stock))
        stocksOnScreenListInfo = placeholder
        time.sleep(5)
  • 您正在将此函数中的stocksOnScreenListInfo分配给一个新列表placeholder。您要做的是修改适当的内容,以便更新main中的stocksOnScreenListInfo。您可以这样做:stocksOnScreenListInfo[:] = placeholder(这意味着使用新列表从头到尾更改内容)

  • stocksOnScreen在for循环中迭代时可能会更改,因为您正在另一个线程中更新它。你应该原子化地做这件事。A lock (您将其作为参数传递给函数)将在这里有所帮助:它是一个同步原语,设计用于在多个线程共享数据且其中至少一个线程修改数据时防止数据争用

我看不到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)

在其他线程函数中:

def screenUpdate_thread(stocksSearchArray, stocksOnScreen):
     while(True):
         stocksOnScreen = UpdateScreen(stocksSearchArray)

您正在将stocksOnScreen分配给此函数中的新列表;它不会影响main中的stocksOnScreen。同样,您可以使用符号stocksOnScreen[:] = new_list来实现这一点。我会在更新stocksOnScreen之前锁定,以确保其他线程函数dataCollector_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作为参数传递给这两个函数

stocksOnScreen = ...更改引用本身。由于引用作为参数传递给函数/线程,因此对函数/线程中原始引用副本进行更改。(两个函数/线程都有自己的副本。)

因此,您应该操作它所引用的列表对象(例如list.clear()list.extend()

但是,正如您所看到的,它现在不再是一个原子操作。所以有可能dataCollector_thread会在一个空列表上工作(即什么都不做)并睡眠5秒钟。我也在下面提供了一个可能的解决方法。但不确定它是否应该(完美地)工作:

def dataCollector_thread(stocksOnScreen):
    while(True):
        sos_copy = stocksOnScreen.copy() # *might* avoid the race?
        for stock in sos_copy:
            print(stock)
        if (len(sos_copy) > 0): # *might* avoid the race?
            time.sleep(5)

def UpdateScreen():
    return ["TSLA"]

def screenUpdate_thread(stocksOnScreen):
    while(True):
        # manipulate the list object instead of changing the reference (copy) in the function
        stocksOnScreen.clear()
        # race condition: dataCollector_thread might work on an empty list and sleep 5 seconds
        stocksOnScreen.extend(UpdateScreen())

def main():
    stocksOnScreen = ["AAPL"] # List of the stocks currently displayed on LED screen

    thread_data_collector = threading.Thread(target=dataCollector_thread, args=(stocksOnScreen,)) # note the comma
    thread_data_collector.daemon = True
    thread_data_collector.start()

    thread_screen = threading.Thread(target=screenUpdate_thread, args=(stocksOnScreen,)) # note the comma
    thread_screen.daemon = True
    thread_screen.start()

注意:根据this answer,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()

参考文献:https://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

这里有三个选项,因为类似python的java通过值传递参数&;不是参考资料

首先,使用全局参数

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))

我希望这回答了你的问题;)

相关问题 更多 >

    热门问题