Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
更新传递到python线程中的变量_Python_Python 3.x_Multithreading_Python Multithreading - Fatal编程技术网

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

更新传递到python线程中的变量,python,python-3.x,multithreading,python-multithreading,Python,Python 3.x,Multithreading,Python Multithreading,我目前在理解线程方面遇到了一些问题,或者可能在理解python中如何通过线程传递/分配变量方面遇到了一些问题。我有一个简单的程序,它接收屏幕上显示的当前股票列表,并获取与这些股票相关的股票信息。我使用线程,这样我可以不断更新屏幕,不断收集数据。我有两个问题: 在dataCollector_-thread()内部,我知道如果我将stocksOnScreenListInfo附加到main中,那么main中的变量(stocksOnScreenListInfo)将被更新 但是,我不想附加到列表中,而只是

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

  • 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
      (这意味着使用新列表从头到尾更改内容)

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

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