如何永久运行一个脚本?

104

我需要在一个无限循环中一直运行我的Python程序。

目前我是这样运行它的 -

#!/usr/bin/python

import time

# some python code that I want 
# to keep on running


# Is this the right way to run the python program forever?
# And do I even need this time.sleep call?
while True:
    time.sleep(5)

有更好的做法吗?或者我是否需要调用time.sleep函数?你有什么想法吗?


那将是正确的做法。只要在“while True:”行下面缩进一些代码(最少可以是pass),就不需要time.sleep(5) - Holy Mackerel
1
如果你想要退出而不是杀死进程,最好添加一个“关闭挂钩”(shutdown hook)作为中断条件。 - user3020494
8
但如果你不睡觉,或者做一些需要等待外部事件(比如监听套接字上的连接或数据)的事情,那么你的程序会使用100%的CPU资源,也就是所谓的“忙等待”(busywait)。这样做是不礼貌的 :) - qris
Python 3.5可以使用asyncio并将函数绑定到事件上。带有GUI的程序可以处理UI事件循环(例如gtk.main())。 - eri
8个回答

116

是的,你可以使用一个永不中断的while True:循环来持续运行Python代码。

然而,你需要将想要持续运行的代码放在循环内部

#!/usr/bin/python

while True:
    # some python code that I want 
    # to keep on running

此外,time.sleep 用于暂停脚本的操作一段时间。因此,既然您希望脚本持续运行,我不明白为什么要使用它。

当通过 .bat 文件启动 Python 代码时,while True 似乎无法正常工作。 - BossRoyce
2
time.sleep 可以通过等待例如 1 毫秒而不是以最大速度运行来提高性能吗? - TOPKAT
@GLAND_PROPRE:优化什么的性能? - martineau
@martineau 对不起,我来自JavaScript背景,在那里如果您不设置“帧限制”,while循环会冻结进程,消耗所有CPU。因此,我想象在每个迭代之间放置1ms的time.sleep将避免进程消耗所有CPU。但我认为我不完全理解Python中如何处理这个问题... - TOPKAT

48

这个怎么样?

import signal
signal.pause()

这将使您的程序休眠,直到它接收到来自其他进程(或另一个线程中的自身)的信号,让它知道是时候做些什么了。


2
信号将停止线程。标题是关于永久运行的。就像系统服务或守护进程。 - outoftime
1
这会停止只有主线程,让其他线程无限运行吗? - David V.
@David 是的,这只停止了主线程。我刚刚测试过以确认。 - Samuel

21

我知道这个帖子太老了,但为什么没有人提到这一点呢?

#!/usr/bin/python3
import asyncio 

loop = asyncio.get_event_loop()
try:
    loop.run_forever()
finally:
    loop.close()

1
我总是在尝试让我的程序永远运行时使用这个。我不知道为什么没有人提到过这一点。 - madladzen
12
如果使用简单的 while True: 就能完成任务,那么为什么还需要包含一个库呢?这样做有什么优缺点,请在您的答案中更新细节。 - Yogesh
1
和Yogesh一样,我想知道这里的理由。 - jason m

15
睡眠是避免CPU过载的好方法。 不确定是否真的聪明,但我通常使用。
while(not sleep(5)):
    #code to execute

sleep方法始终返回None。


2
被无评论downvote了?我喜欢这个解决方案,因为它具有良好的可读性/可维护性。一个对这段代码感兴趣的读者不需要滚动查找循环间隔。 - Matt
1
@mustafa 哪一个?解释一下,它完美地运行。 - NIEL Alexandre
7
它在第一次执行之前不会睡眠吗?我认为这通常不是期望的行为。 - noonex

6
这里是完整的语法:
#!/usr/bin/python3

import time 

def your_function():
    print("Hello, World")

while True:
    your_function()
    time.sleep(10) #make function to sleep for 10 seconds

4

对于支持select的操作系统:

import select

# your code

select.select([], [], [])

1
我有一个小脚本interruptableloop.py,它以间隔(默认1秒)运行代码,同时在运行时向屏幕输出一条消息,并捕获您可以使用CTL-C发送的中断信号:
#!/usr/bin/python3
from interruptableLoop import InterruptableLoop

loop=InterruptableLoop(intervalSecs=1) # redundant argument
while loop.ShouldContinue():
   # some python code that I want 
   # to keep on running
   pass

当您运行脚本并中断它时,会看到此输出(循环的每次迭代都会输出句点):
[py36]$ ./interruptexample.py
CTL-C to stop   (or $kill -s SIGINT pid)
......^C
Exiting at  2018-07-28 14:58:40.359331

interruptableLoop.py:

"""
    Use to create a permanent loop that can be stopped ...

    ... from same terminal where process was started and is running in foreground: 
        CTL-C

    ... from same user account but through a different terminal 
        $ kill -2 <pid> 
        or $ kill -s SIGINT <pid>

"""
import signal
import time
from datetime import datetime as dtt
__all__=["InterruptableLoop",]
class InterruptableLoop:
    def __init__(self,intervalSecs=1,printStatus=True):
        self.intervalSecs=intervalSecs
        self.shouldContinue=True
        self.printStatus=printStatus
        self.interrupted=False
        if self.printStatus:
            print ("CTL-C to stop\t(or $kill -s SIGINT pid)")
        signal.signal(signal.SIGINT, self._StopRunning)
        signal.signal(signal.SIGQUIT, self._Abort)
        signal.signal(signal.SIGTERM, self._Abort)

    def _StopRunning(self, signal, frame):
        self.shouldContinue = False

    def _Abort(self, signal, frame):
        raise 

    def ShouldContinue(self):
        time.sleep(self.intervalSecs)
        if self.shouldContinue and self.printStatus: 
            print( ".",end="",flush=True)
        elif not self.shouldContinue and self.printStatus:
            print ("Exiting at ",dtt.now())
        return self.shouldContinue

难道只需在客户端代码中捕获KeyboardInterruptSystemExit异常,而不是为此专门创建一个类,这样不是更容易(也更符合Python风格)吗? - Matthew Cole
我使用这个封装,我喜欢它的阅读方式。当我使用它时,显然interruptableloop的实现不会在我的脑海中运行。 - Rian Rizvi

0

如果您的意思是作为服务运行,那么您可以使用任何REST框架。

from flask import Flask
class A:
    def one(port):
        app = Flask(__name__)
        app.run(port = port)
        

调用它:

one(port=1001)

它将始终在1001上保持监听

 * Running on http://127.0.0.1:1001/ (Press CTRL+C to quit)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接