【问题标题】:Threading the same function for a different result in Python在 Python 中为不同的结果线程化相同的函数
【发布时间】:2012-06-05 13:07:14
【问题描述】:

我需要我的程序并行执行某个功能。但是根据用户与程序的交互方式,该功能会产生不同的结果。我在一个名为 threadGUI.py 的模块中有一个简单的 GUI,它有两个选项:下载和上传。这些选项创建包含与函数相关的变量的字典。这些字典存储在主字典中,主字典存储在 thread_test.py 模块中。这些在一个接一个地执行时工作正常,但是当我尝试并行执行时出现问题。 threadGUI.py中的线程相关代码:

def OnStartClick(self):
  for i in thread_test.dictList.values():        #the main dictionary is stored as a global in thread_test.py
     thread = Thread(target = thread_test.begin_tests, args = (i, ))
     thread.start()
  print "thread finished...exiting"

上述函数调用thread_test.py模块中的begin_test函数。函数如下所示:

def begin_tests(arg): 
    print arg
    print dictList
    dictItem = arg
    print dictItem
    if dictItem['Type'] == "HTTP_Downloading":
        print "DOWNLOAD"
    elif dictItem['Type'] == "FTP_Uploading":
        print "UPLOAD"
    else:
        print "Invalid input"
        sys.exit(1)

这是我的代码的简化示例。我的问题是我的代码只执行两个函数中的一个,而不是两个函数。因此,如果我创建了一个名为下载、上传、下载的字典,那么它将执行三个下载,而不是所需的模式。

【问题讨论】:

    标签: python function if-statement module python-multithreading


    【解决方案1】:

    问题不在贴出的代码中:

    from threading import Thread
    
    dictList = {
        'foo': { 'Type': 'HTTP_Downloading' },
        'bar': { 'Type': 'FTP_Uploading' },
        'baz': { 'Type': 'HTTP_Downloading' }
    }
    
    def begin_tests(arg):
        print arg
        print dictList
        dictItem = arg
        print dictItem
        if dictItem['Type'] == "HTTP_Downloading":
            print "DOWNLOAD"
        elif dictItem['Type'] == "FTP_Uploading":
            print "UPLOAD"
        else:
            print "Invalid input"
            sys.exit(1)
    
    def OnStartClick(self):
      for i in dictList.values():        #the main dictionary is stored as a global in thread_test.py
         thread = Thread(target = begin_tests, args = (i, ))
         thread.start()
      print "thread finished...exiting"
    
    OnStartClick(None)
    

    结果:

    {'Type': 'HTTP_Downloading'}
    {'baz': {'Type': 'HTTP_Downloading'}, 'foo': {'Type': 'HTTP_Downloading'}, 'bar': {'Type': 'FTP_Uploading'}}
    {'Type': 'HTTP_Downloading'}
     {DOWNLOAD
    {'Type': 'FTP_Uploading'}
    'Type': 'HTTP_Downloading'}
    {'baz': {'Type': 'HTTP_Downloading'}, 'foo': {'Type': 'HTTP_Downloading'}, 'bar': {'Type': 'FTP_Uploading'}}
    {'baz': {'Type': 'HTTP_Downloading'}, 'foo': {'Type': 'HTTP_Downloading'}, 'bar': {'Type': 'FTP_Uploading'}}
     thread finished...exiting
    {'Type': 'HTTP_Downloading'}
    DOWNLOAD
    {'Type': 'FTP_Uploading'}
    UPLOAD
    

    猜测,你正在重用内部字典。

    更新:

    我认为这种情况最好通过使用工作池和队列策略来解决。比如:

    from Queue import Queue
    from threading import Thread
    
    queue = Queue() # Replaces the dictList
    
    threads = []
    for n in range(10):
        thread = Thread(target = worker, args = (begin_tests, queue, ))
        thread.start()
        threads.append(thread)
    
    Stop = object()
    def worker(work, queue):
        while True:
            task = queue.get()
            if task is Stop:
                break
            work(task)            
    

    像这样使用它:

    queue.put({ 'Type': 'HTTP_Downloading' })
    queue.put({ 'Type': 'FTP_Uploading' })
    queue.put({ 'Type': 'HTTP_Downloading' })
    queue.put(Stop)
    

    这本身并不能解决改变字典的问题;这必须在其他地方修复。这种策略有两个好处:它确实保留了任务的顺序,并且不会冒丢失任务的风险:dict 提供有限的并发保证,而 Queue() 保证是线程安全的。

    【讨论】:

    • 我在发布我的问题后不久就意识到了这一点,所以你的猜测是正确的。我目前不知道如何解决。一旦下一个线程启动,它就会覆盖 dictItem 并在任何先前正在进行的线程中导致错误。有没有办法将全局变量固定到该特定线程而不影响所有线程?
    • 队列听起来不错,但是这个程序太远了,现在无法切换。也许如果我最后有时间优化代码,我可以试一试。事实证明我对全局变量的影响太大了,我发现本地线程存储解决了我的问题。无论如何感谢您的帮助,它帮助我缩小了问题范围!
    猜你喜欢
    • 1970-01-01
    • 2021-04-02
    • 2019-08-29
    • 2020-07-28
    • 1970-01-01
    • 2020-02-09
    • 2014-03-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多