螺纹扭曲...如何正确使用它们?

发布于 2024-08-21 06:17:29 字数 1081 浏览 7 评论 0原文

我需要编写一个运行两个线程的简单应用程序: - 线程 1:按定时运行,假设每 1 分钟运行一次 - 线程2:只是一个“正常”的 while True 循环,如果不需要按定时间隔运行,它会做“填充”,

我根本不会考虑扭曲,但简单的 sleep(60) 还不够好,构造如下:

l = task.LoopingCall(timed_thread)
l.start(60.0)
reactor.run()

看起来很简单就能实现我想要的目标。

现在,我如何“正确”添加另一个线程?

我在这里看到两个选项:

  • 使用线程库并运行两个“python 线程”,一个执行我的 while 循环,另一个运行reactor.run()。但谷歌似乎反对这种方法,并建议使用扭曲线程
  • 。这就是我尝试过的,但不知怎的,这对我来说看起来有点笨拙。

这就是我的想法:

def timed_thread():
    print 'i will be called every 1 minute'
    return

def normal_thread():
    print 'this is a normal thread'
    time.sleep(30)
    return

l = task.LoopingCall(timed_thread)
l.start(60.0)
reactor.callInThread(normal_thread)
reactor.run()

这似乎可行,但是!我无法停止该应用程序。如果我按 ^C 它不会执行任何操作(如果没有“callInThread”,它只会像您期望的那样停止)。 ^Z 轰炸到 shell,如果我然后执行“kill %1”,它似乎会杀死该进程(shell 报告这一点),但“正常”线程继续运行。 kill PID 并不能消除它,唯一的解决办法是kill -9。真的很奇怪。

所以。我做错了什么?在twisted中实现两个线程是正确的方法吗?我不应该为扭曲而烦恼吗?还有哪些其他“标准”替代方案可以实现定时调用? (“标准”我的意思是我可以 easy_install 或 yum 安装它们,我不想开始从随机网页下载和使用一些随机脚本)。

I need to write a simple app that runs two threads:
- thread 1: runs at timed periods, let's say every 1 minute
- thread 2: just a 'normal' while True loop that does 'stuff'

if not the requirement to run at timed interval I would have not looked at twisted at all, but simple sleep(60) is not good enough and construction like:

l = task.LoopingCall(timed_thread)
l.start(60.0)
reactor.run()

Looked really simple to achieve what I wanted there.

Now, how do I 'properly' add another thread?

I see two options here:

  • Use threading library and run two 'python threads' one executing my while loop, and another running reactor.run(). But Google seems to object this approach and suggests using twisted threading
  • Use twisted threading. That's what I've tried, but somehow this looks bit clumsy to me.

Here's what I came up with:

def timed_thread():
    print 'i will be called every 1 minute'
    return

def normal_thread():
    print 'this is a normal thread'
    time.sleep(30)
    return

l = task.LoopingCall(timed_thread)
l.start(60.0)
reactor.callInThread(normal_thread)
reactor.run()

That seems to work, but! I can't stop the app. If I press ^C it wouldn't do anything (without 'callInThread' it just stops as you'd expect it to). ^Z bombs out to shell, and if I then do 'kill %1' it seems to kill the process (shell reports that), but the 'normal' thread keeps on running. kill PID wouldn't get rid of it, and the only cure is kill -9. Really strange.

So. What am I doing wrong? Is it a correct approach to implement two threads in twisted? Should I not bother with twisted? What other 'standard' alternatives are to implement timed calls? ('Standard' I mean I can easy_install or yum install them, I don't want to start downloading and using some random scripts from random web pages).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烟织青萝梦 2024-08-28 06:17:29

您没有解释为什么这里实际上需要线程。如果您有的话,我也许能够解释为什么您不需要它们。 ;)

除此之外,我可以确认您对事物的基本理解是正确的。不过,我可以澄清的一个可能的误解是“python 线程”和“Twisted 线程”完全不同的概念。他们不是。 Python提供了一个线程库。 Twisted 的所有线程 API 都是根据 Python 线程库实现的。只是API不同。

就关闭而言,您有两种选择。

  • 直接使用 Python 的线程 API 启动永远运行的线程,并使该线程成为守护进程。即使守护线程仍在运行,您的进程也可以退出。此解决方案可能存在的问题是,某些版本的 Python 存在守护线程问题,这会导致关闭时崩溃。
  • 使用 Twisted 的 API 或 stdlib 线程 API 创建线程,同时使用 reactor.addSystemEventTrigger('before', 'shutdown', f) 添加 Twisted 关闭挂钩。在该钩子中,与工作线程通信并告诉它关闭。例如,您可以在 Twisted 线程和工作线程之间共享一个 threading.Event 并让钩子设置它。工作线程可以定期检查它是否已设置,并在发现已设置时退出。除了不崩溃之外,这还比守护线程有另一个优势 - 它允许您在进程退出之前在工作线程中运行一些清理或终结代码。

You didn't explain why you actually need threads here. If you had, I might have been able to explain why you don't need them. ;)

That aside, I can confirm that your basic understanding of things is correct. One possible misunderstanding I can clear up, though, is the notion that "python threads" and "Twisted threads" are at all different from each other. They're not. Python provides a threading library. All of Twisted's thread APIs are implemented in terms of Python's threading library. Only the API is different.

As far as shutdown goes, you have two options.

  • Start your run-forever thread using Python's threading APIs directly and make the thread a daemon. Your process can exit even while daemon threads are still running. A possible problem with this solution is that some versions of Python have issues with daemon threads that will lead to a crash at shutdown time.
  • Create your thread using either Twisted's APIs or the stdlib threading APIs but also add a Twisted shutdown hook using reactor.addSystemEventTrigger('before', 'shutdown', f). In that hook, communicate with the work thread and tell it to shut down. For example, you could share a threading.Event between the Twisted thread and your work thread and have the hook set it. The work thread can periodically check to see if it has been set and exit when it notices that it has been. Aside from not crashing, this gives another advantage over daemon threads - it will let you run some cleanup or finalization code in your work thread before the process exits.
隐诗 2024-08-28 06:17:29

假设你的 main 是相对非阻塞的:

import random
from twisted.internet import task

class MyProcess:
  def __init__(self):
    self.stats = []
    self.lp = None
  def myloopingCall(self):
    print "I have %s stats" % len(self.stats)
  def myMainFunction(self,reactor):
    self.stats.append(random.random())
    reactor.callLater(0,self.myMainFunction,reactor)
  def start(self,reactor):
    self.lp = task.LoopingCall(self.myloopingCall)
    self.lp.start(2)
    reactor.callLater(0,self.myMainFunction,reactor)
  def stop(self):
    if self.lp is not None:
      self.lp.stop()
    print "I'm done"

if __name__ == '__main__':
  myproc = MyProcess()
  from twisted.internet import reactor
  reactor.callWhenRunning(myproc.start,reactor)
  reactor.addSystemEventTrigger('during','shutdown',myproc.stop)
  reactor.callLater(10,reactor.stop)
  reactor.run()
$ python bleh.py
I have 0 stats
I have 33375 stats
I have 66786 stats
I have 100254 stats
I have 133625 stats
I'm done

Assuming that your main is relatively non-blocking:

import random
from twisted.internet import task

class MyProcess:
  def __init__(self):
    self.stats = []
    self.lp = None
  def myloopingCall(self):
    print "I have %s stats" % len(self.stats)
  def myMainFunction(self,reactor):
    self.stats.append(random.random())
    reactor.callLater(0,self.myMainFunction,reactor)
  def start(self,reactor):
    self.lp = task.LoopingCall(self.myloopingCall)
    self.lp.start(2)
    reactor.callLater(0,self.myMainFunction,reactor)
  def stop(self):
    if self.lp is not None:
      self.lp.stop()
    print "I'm done"

if __name__ == '__main__':
  myproc = MyProcess()
  from twisted.internet import reactor
  reactor.callWhenRunning(myproc.start,reactor)
  reactor.addSystemEventTrigger('during','shutdown',myproc.stop)
  reactor.callLater(10,reactor.stop)
  reactor.run()
$ python bleh.py
I have 0 stats
I have 33375 stats
I have 66786 stats
I have 100254 stats
I have 133625 stats
I'm done
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文