【问题标题】:Python, non-blocking threadsPython,非阻塞线程
【发布时间】:2014-02-18 21:04:57
【问题描述】:

有很多关于 Python 和异步编码技术的教程等,但我很难过滤结果以找到我需要的东西。我是 Python 新手,所以这无济于事。

设置

我目前有两个看起来像这样的对象(请原谅我的 python 格式):

class Alphabet(parent):
    def init(self, item):
        self.item = item

    def style_alphabet(callback):
        # this method presumably takes a very long time, and fills out some properties
        # of the Alphabet object
        callback()


class myobj(another_parent):
    def init(self):
        self.alphabets = []
        refresh()
        
    def foo(self):
        for item in ['a', 'b', 'c']:
            letters = new Alphabet(item)
            self.alphabets.append(letters)
        self.screen_refresh()

        for item in self.alphabets
            # this is the code that I want to run asynchronously. Typically, my efforts
            # all involve passing item.style_alphabet to the async object / method
            # and either calling start() here or in Alphabet
            item.style_alphabet(self.screen_refresh)
            
    def refresh(self):
        foo()
        # redraw screen, using the refreshed alphabets
        redraw_screen()

    def screen_refresh(self):
        # a lighter version of refresh()
        redraw_screen()

这个想法是,主线程最初用不完整的Alphabet 对象绘制屏幕,​​填充字母对象,完成后更新屏幕。

我尝试了许多 threading.Tread、Queue.Queue 甚至期货的实现,但由于某种原因,它们要么没有工作,要么阻塞了主线程。这样就不会发生初始抽签。

我尝试过的一些异步方法:

class Async (threading.Thread):
    def __init__(self, f, cb):
        threading.Thread.__init__(self)
        self.f  = f
        self.cb = cb

    def run(self):
        self.f()
        self.cb()

def run_as_thread(f):
    # When I tried this method, I assigned the callback to a property of "Alphabet"
    thr = threading.Thread(target=f)
    thr.start()

def run_async(f, cb):
    pool = Pool(processes=1)
    result = pool.apply_async(func=f, args=args, callback=cb)

【问题讨论】:

  • 您能告诉我们您是如何实例化您的Async 类并调用它的start() 方法(同样适用于run_as_thread())吗?
  • 另外,在myobj.foo() 的最后一个块中调用letters.style_alphabet() 可能不是您想要的(应该是item.style_alphabet(),不是吗?)。但我猜这是某种类型的剪切和过去错误,因为这显然不是您尝试运行的实际代码。
  • Twisted 框架为您提供了您正在寻找的东西...如果您想让我具体说明...结帐 thread.deferToThread() 。它可以满足您的需求...
  • 感谢您注意到字母/项目错误,Alp - 它已修复
  • Alp - Async 类和 run_as_thread() 方法已完成,这是我的问题吗?我以前从来没有做过这种事情。

标签: python python-2.7 asynchronous


【解决方案1】:

我最终编写了一个线程池来处理这种使用模式。尝试创建一个队列并将引用传递给所有工作线程。从主线程将任务对象添加到队列中。工作线程从队列中拉取对象并调用函数。为每个任务添加一个事件,以在任务完成时在工作线程上发出信号。在主线程上保留一个任务对象列表,并使用轮询来查看 UI 是否需要更新。如果需要,可以花点时间在任务对象上添加一个指向回调函数的指针。

我的解决方案灵感来自我在 Google 上找到的内容:http://code.activestate.com/recipes/577187-python-thread-pool/

我不断改进该设计以添加功能并为线程、多处理和并行 python 模块提供一致的接口。我的实现在:

https://github.com/nornir/nornir-pools

文档:

http://nornir.github.io/packages/nornir_pools.html

如果您是 Python 新手并且不熟悉 GIL,我建议您搜索 Python 线程和全局解释器锁 (GIL)。这不是一个快乐的故事。一般来说,我发现我需要使用多处理模块才能获得不错的性能。

希望这能有所帮助。

【讨论】:

  • 感谢领导,Xycor,欢迎来到 SO!您的答案在我的尝试清单上,但是您发布到 git 存储库的链接已损坏。你能解决它吗?
  • 当您说“多线程”时,您的意思是multiprocessing,它通过使用子进程而不是线程来绕过 GIL 问题?
  • 我对python还不够熟悉可以说。我的目标是运行一些不干扰主线程的代码,然后在主线程上调用一个方法来更新屏幕。我正在尝试创建一个“响应式 gui”
  • 修复了模块的链接和名称。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 2019-02-12
  • 2013-05-24
  • 1970-01-01
  • 2012-06-13
相关资源
最近更新 更多