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'
我需要编写一个简单的应用程序,它运行两个线程:线程1:按时间周期运行,假设每1分钟运行一次——线程2:一个执行“stuff”的“normal”和“True”循环
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:
如果不是要求按时间间隔运行的话,我根本就不会考虑twisted,但是简单的睡眠(60)还不够好,构造也不太好:
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
- 使用线程库并运行两个“python线程”,一个执行while循环,另一个运行。run()。但是谷歌似乎反对这种方法,并建议使用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.
这似乎行得通,但是!我不能停止应用程序。如果我按^ C它不会做任何事情(没有“callInThread”它就停止你期望它)。^ Z炸弹壳,然后如果我做“杀死% 1”似乎杀死进程(shell报道),但“正常”线程继续运行。杀死PID是无法摆脱的,唯一的治疗方法是杀死-9。真的奇怪。
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).
所以。我做错了什么?在twisted中实现两个线程是正确的方法吗?我不应该被扭曲困扰吗?其他的“标准”选择是什么来实现定时通话?(“标准”我的意思是我可以轻松安装或yum安装它们,我不想开始从随机的web页面下载和使用一些随机脚本)。
2 个解决方案
#1
2
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
#2
5
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.
除此之外,我可以肯定你对事情的基本理解是正确的。不过,我可以澄清的一个可能的误解是,“python线程”和“Twisted线程”是完全不同的。他们不是。Python提供了一个线程库。所有Twisted的线程api都是根据Python的线程库实现的。只有API不同。
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.
- 使用Python的线程api直接启动run-forever线程,使线程成为一个守护进程。您的进程可以退出,即使守护进程线程仍在运行。此解决方案的一个可能问题是,某些版本的Python与守护进程线程存在问题,这将导致在关闭时崩溃。
- 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 athreading.Event
between the Twisted thread and your work thread and have the hookset
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. - 使用Twisted的api或stdlib线程api创建您的线程,还可以使用反应器添加一个Twisted shutdown hook。addSystemEventTrigger(“before”,“shutdown”,f)。在这个钩子中,与工作线程通信,并告诉它关闭。例如,您可以共享线程。在扭曲的线和你的工作线之间的事件,并让钩设置它。工作线程可以定期检查它是否已设置,并在发现它已设置时退出。除了不崩溃之外,这将给守护线程带来另一个优势——在进程退出之前,它将让您在工作线程中运行一些清理或终结代码。
#1
2
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
#2
5
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.
除此之外,我可以肯定你对事情的基本理解是正确的。不过,我可以澄清的一个可能的误解是,“python线程”和“Twisted线程”是完全不同的。他们不是。Python提供了一个线程库。所有Twisted的线程api都是根据Python的线程库实现的。只有API不同。
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.
- 使用Python的线程api直接启动run-forever线程,使线程成为一个守护进程。您的进程可以退出,即使守护进程线程仍在运行。此解决方案的一个可能问题是,某些版本的Python与守护进程线程存在问题,这将导致在关闭时崩溃。
- 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 athreading.Event
between the Twisted thread and your work thread and have the hookset
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. - 使用Twisted的api或stdlib线程api创建您的线程,还可以使用反应器添加一个Twisted shutdown hook。addSystemEventTrigger(“before”,“shutdown”,f)。在这个钩子中,与工作线程通信,并告诉它关闭。例如,您可以共享线程。在扭曲的线和你的工作线之间的事件,并让钩设置它。工作线程可以定期检查它是否已设置,并在发现它已设置时退出。除了不崩溃之外,这将给守护线程带来另一个优势——在进程退出之前,它将让您在工作线程中运行一些清理或终结代码。