Python线程传递状态

时间:2010-09-19 15:31:14

标签: python multithreading

基本上我要做的是使用代理获取几个网站并处理数据。问题是请求很少以令人信服的方式失败,设置套接字超时不是很有帮助,因为它们通常不起作用。

所以我做的是:

q = Queue()
s = ['google.com','ebay.com',] # And so on
for item in s:
    q.put(item)


def worker():
        item = q.get()
        data = fetch(item) # This is the buggy part
        # Process the data, yadayada

for i in range(workers):
    t = InterruptableThread(target=worker)
    t.start()


# Somewhere else
if WorkerHasLivedLongerThanTimeout:
    worker.terminate()

(InterruptableThread class) 问题是我只想杀死仍然卡在提取部分的线程。此外,我希望该项目返回队列。即:

def worker():
        self.status = 0
        item = q.get()
        data = fetch(item) # This is the buggy part
        self.status = 1 # Don't kill me now, bro!
        # Process the data, yadayada

# Somewhere else
if WorkerHasLivedLongerThanTimeout and worker.status != 1:
    q.put(worker.item)
    worker.terminate()

如何做到这一点?

1 个答案:

答案 0 :(得分:1)

编辑:突发新闻;见下面··········

我最近决定要做一些非常相似的事情,其中​​出现的是pqueue_fetcher模块。它最终主要是一项学习努力:除其他事项外,我了解到使用twisted之类的东西几乎肯定比尝试以任何可靠性杀死Python线程更好。

话虽如此,该模块中的代码或多或少地回答了您的问题。它基本上由一个类组成,其对象可以设置为从优先级队列中获取位置,并将它们提供给在对象实例化时提供的fetch函数。如果在线程被杀死之前成功接收到位置的资源,它们将被转发到results队列;否则他们将以降级的优先级返回locations队列。成功取决于传入函数,默认为bool

在此过程中,我最终创建了terminable_thread模块,该模块只将我链接到的代码中最成熟的变体打包为InterruptableThread。它还为64位机器添加了一个修复程序,为了在我的ubuntu机器上使用该代码,我需要它。 terminable_threadpqueue_fetcher的依赖关系。

我遇到的最大绊脚石可能是像terminable_thread那样引发异步异常,而你提到的InterruptableThread可能会产生一些奇怪的结果。在pqueue_fetcher的测试套件中,fetch功能会通过调用time.sleep来阻止。我发现如果一个线程terminate() d而阻塞,并且sleep调用是嵌套try块中的最后一个(或者不是最后一个)语句,则执行实际上会跳转到{{ 1}} 外部 的块子尝试块,即使内部的except与引发的异常匹配。我仍然难以置信地摇头,但except中有一个测试用例重演了这个问题。我认为“漏洞抽象”是正确的术语。

我编写了一个hacky解决方法,只是做一些随机的事情(在这种情况下从生成器获取一个值)来打破代码部分的“原子性”(不确定它是否真的是它)。可以通过pqueue_fetcher参数将此解决方法覆盖为fission。它(即默认的)似乎有效,但肯定不会以任何方式我认为特别可靠或便携。

因此,在发现这个有趣的数据之后,我的呼吁是迄今为止避免使用这种技术(即调用pqueue_fetcher.Fetcher)。

在任何情况下,如果您需要保证已收到整个数据集(并且已向服务器确认)的任何请求转发到ctypes.pythonapi.PyThreadState_SetAsyncExc,则仍然无法使用。为了确保这一点,您必须保证执行该最后一次网络事务和转发的位被防止被中断,而不保护整个检索操作不被中断(因为这会阻止超时工作......) 。为了做到这一点,您需要基本上重写检索操作(即套接字代码),以便了解您将使用results引发的任何异常。

我还没学会扭曲,但作为Premier Python异步网络框架©™®,我希望它必须有一些优雅或至少可行的方式来处理这些细节。我希望它提供一种并行的方式来实现从非网络源(例如本地文件存储,或数据库等)的提取,因为我想构建一个可以从各种各样的数据中收集数据的应用程序。以中等不可知的方式来源。

无论如何,如果你仍然想要尝试自己管理线程的方法,你也许可以从我的努力中学习。希望这会有所帮助。

··········这只是在:

我意识到我认为已经稳定的测试实际上没有,并且给出了不一致的结果。这似乎与上面提到的异常处理和terminable_thread.Thread.raise_exc函数的使用有关。我不确定它发生了什么,并且不打算在不久的将来进行调查,除非我最终需要以这种方式实际做事。