计时器阻止程序退出



我正在编写一个程序,该程序允许我使用python控制一个普通的Minecraft服务器。我想做的第一件事是自动重启功能。一切都很好,除了我不能做sys.exit()或类似的事情,我不确定,但我认为这是因为Timer

我试过t.cancel(),但t是一个局部变量,所以使用它很复杂

这是我的代码:

#! /usr/bin/env python3
import os, sys, time
import subprocess
from datetime import datetime, timedelta, date
from threading import Timer
server = subprocess.Popen('./start.sh', stdin=subprocess.PIPE,shell=True)
#junk variables
content = ''
previousContent = ''
def restart():
if datetime.today().weekday() is 3:
server.stdin.write(bytes('stoprn', 'ascii'))
server.stdin.flush()
time.sleep(90)
print('Restarting...')
os.system('python3 start.py')
sys.exit()
else:
timerStart()
def timerStart():
today = datetime.today()
restartDate = today.replace(day=today.day,hour=1,minute=0,second=0,microsecond=0) + timedelta(days=1)
delta_t = restartDate-today
secs= delta_t.total_seconds()
t=Timer(secs, restart)
t.start()
timerStart()
while True:
time.sleep(0.1)

#stdout
f = open('logs/latest.log')
content = f.read()
if previousContent != '':
if previousContent in content:
content.replace(previousContent,'')
if content != '':
print(content)
previousContent = f.read()
f.close()
#stdin
command = input('')
if command:
if command == 'stop':
server.stdin.write(bytes('stoprn', 'ascii'))
server.stdin.flush()
time.sleep(20)
sys.exit()
else:
server.stdin.write(bytes(command + 'rn', 'ascii'))
server.stdin.flush()

如果有人至少能让我走上正轨,这将真正帮助我

实例化线程时。Timer类,并在相应的对象中调用其start((方法,创建一个新的非守护进程执行线程并在后台启动以执行方法";重新启动";。所创建的执行线程等待在";秒;变量。计时器类经过,然后执行指定的";重新启动";方法当您调用sys.exit((时,脚本的执行不会结束,原因是应用程序的主执行线程为了完成其执行(从而完成脚本的执行(,必须等待创建的所有其他非守护进程线程首先完成。也就是说,当您调用进程的主执行线程sys.exit((时,将不得不等待线程实例化创建的线程。计时器类,以完成其执行。要解决这个问题,正如您所提到的,您可以调用t.cancel((;t〃;到全局范围,以便能够在"timerStart"函数中使用它,并在执行以处理";停止";命令例如,在变量"的声明和初始化之后;previousContent";,您可以在那里声明变量t,并将其初始化为None。然后,在将线程实例分配给它之前。计时器,您必须使用";全局";关键字,该关键字允许在当前作用域之外(在"timerStart"函数的作用域之外(修改变量,最后,在处理";停止";命令,调用t.cancel((。简而言之,最终代码如下所示:

# ! /usr/bin/env python3
import os, sys, time
import subprocess
from datetime import datetime, timedelta, date
from threading import Timer
server = subprocess.Popen('./start.sh', stdin=subprocess.PIPE, shell=True)
# junk variables
content = ''
previousContent = ''
t = None

def restart():
if datetime.today().weekday() is 3:
server.stdin.write(bytes('stoprn', 'ascii'))
server.stdin.flush()
time.sleep(90)
print('Restarting...')
os.system('python3 start.py')
sys.exit()
else:
timerStart()

def timerStart():
today = datetime.today()
restartDate = today.replace(day=today.day, hour=1, minute=0, second=0, microsecond=0) + timedelta(days=1)
delta_t = restartDate - today
secs = delta_t.total_seconds()
global t
t = Timer(secs, restart)
t.start()

timerStart()
while True:
time.sleep(0.1)
# stdout
with open('logs/latest.log') as f:
# Is better to open the file using a "with", such that the file is guaranteed to be closed,
# even in the case of an exception
content = f.read()
if previousContent != '':
if previousContent in content:
content.replace(previousContent, '')
if content != '':
print(content)
previousContent = f.read()
# stdin
command = input('')
if command:
if command == 'stop':
# Abort the threading.Timer's non-daemon execution thread:
t.cancel()
# Blocks the calling thread until the thread whose join() method is called is terminated:
t.join()
server.stdin.write(bytes('stoprn', 'ascii'))
server.stdin.flush()
time.sleep(20)
sys.exit()
else:
server.stdin.write(bytes(command + 'rn', 'ascii'))
server.stdin.flush()

此外,很高兴知道通过实例化线程创建的线程。定时器类,可以取消,只有在它开始执行";重新启动";方法类线程。计时器,继承自线程。线程,也就是说,当调用start((时,它创建并激发新的非守护进程执行线程的执行。

参考文献:

计时器对象线程对象

如果您对线程所做的唯一事情就是重新启动脚本,那么您可以尝试更简单的方法。如果您为计时器中断设置了一个信号处理程序,然后启动一个计时器,该计时器将在您希望代码重新启动时启动,则可以跳过所有线程处理。

#!/usr/bin/env python3
import signal
...other imports...
def do_restart(signal_num, frame):
server.stdin.write(bytes('stoprn', 'ascii'))
server.stdin.flush()
time.sleep(90)
print('Restarting...')
os.system('python3 start.py')
sys.exit()
...calculate how long before the restart...
signal.signal(signal.SIGALRM, do_restart)
signal.alarm(seconds_until_restart)
while True:
time.sleep(0.1)

#stdout
f = open('logs/latest.log')
content = f.read()
if previousContent != '':
if previousContent in content:
content.replace(previousContent,'')
if content != '':
print(content)
previousContent = f.read()
f.close()
#stdin
command = input('')
if command:
if command == 'stop':
server.stdin.write(bytes('stoprn', 'ascii'))
server.stdin.flush()
time.sleep(20)
sys.exit()
else:
server.stdin.write(bytes(command + 'rn', 'ascii'))
server.stdin.flush()