我的Python-MYSQL程序在运行几个小时后会永远休眠,但这不是内存泄漏。



下面是一个稍微评分的Python 3.7程序,在我的RaspberryPi上的Linux上运行几个小时后,它显然进入睡眠状态(0%cpu,但根据htop仍然存在(。我已经编程让它对 STRG+C 做出反应,睡觉后,它仍然对 STRG+C 做出反应,但我想这仍然意味着它已经睡着了。自启动以来,它没有获得任何内存,仍然为 22MB, 我还使用探查器来检查是否没有任何内存泄漏。 光标在下一行,程序不再反应......

import mysql.connector, time, signal, requests
from mysql.connector import errorcode

USER = ...
PASSWORD = ...
HOST = ...
DATABASE = ...

RUNNING = True

def signal_handler(signum, frame):
global RUNNING
signal.signal(signum, signal.SIG_IGN) # ignore additional signals
print('Received shutdown signal')
print('Treating remaining players as if they just went offline...')
RUNNING = False

def time_string(timestamp, forString = False, brackets = False):
hours = int((timestamp // 3600 + (0 if forString else 2)) % 24)
minutes = int(timestamp // 60 % 60)
seconds = int(timestamp % 60)
shours = ('0' if hours < 10 else '') + str(hours)
sminutes = ('0' if minutes < 10 else '') + str(minutes)
sseconds = ('0' if seconds < 10 else '') + str(seconds)
ret = shours+':'+sminutes+':'+sseconds
if brackets:
ret = '['+ret+']'
return ret

def main():
global USER, PASSWORD, HOST, DATABASE
start_timestamp = None
end_timestamp = None
registeredWhen = dict()
startedOnline = dict()
startedPlaying = dict()

try:
conn = mysql.connector.connect(user=USER, password=PASSWORD, host=HOST, database=DATABASE)
except mysql.connector.Error as err:
if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
print("Something is wrong with your user name or password")
elif err.errno == errorcode.ER_BAD_DB_ERROR:
print("Database does not exist")
else:
print(err)
conn.close()
return

conn.autocommit = True
cursor = conn.cursor(prepared=True)

cursor.execute(
"""
CREATE TABLE IF NOT EXISTS recording_periods(
player TEXT,
start INTEGER,
end INTEGER
)
"""
)
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS online_periods(
player TEXT,
start INTEGER,
end INTEGER
)
"""
)
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS playing_periods(
player TEXT,
start INTEGER,
end INTEGER
)
"""
)
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS players_to_record(
player TEXT
)
"""
)
signal.signal(signal.SIGINT, signal_handler)
last_timestamp = time.time()-1
timestamp = last_timestamp
start_timestamp = None
end_timestamp = None
while RUNNING or [] != [x for x in startedOnline if startedOnline[x] != None]  or [] != [x for x in startedPlaying if startedPlaying[x] != None]:
timestamp = int(time.time())
while timestamp == last_timestamp:
time.sleep(0.01)
timestamp = int(time.time())

cursor.execute("""SELECT player FROM players_to_record""")
nplayers = set([x[0].decode().lower() for x in cursor.fetchall()])
added = set([player for player in nplayers if player not in registeredWhen])
removed = set([player for player in registeredWhen if player not in nplayers])
for player in added:
print('Registered player '+player)
registeredWhen[player] = timestamp
startedOnline[player] = None
startedPlaying[player] = None
info = []
for player in removed:
print('Unregistered player '+player)
info.append((player, registeredWhen[player], end_timestamp))
registeredWhen.pop(player)
startedOnline.pop(player)
startedPlaying.pop(player)
cursor.executemany("""INSERT INTO recording_periods VALUES (?, ?, ?)""", info)
url = 'https://lichess.org/api/users/status?ids='
for player in registeredWhen:
url = url + player +','
url = url[:-1]
try:
resp = requests.get(url)
data = resp.json()
resp.close()
ts = time_string(timestamp, brackets=True)
tsnb = time_string(timestamp, brackets=False)
ronline = []
rplaying = []
for user in data:
name_id = user['id']
name = user['name']
online = 'online' in user and user['online']
playing = 'playing' in user and user['playing']
if start_timestamp == None:
start_timestamp = timestamp
end_timestamp = timestamp
if startedOnline[name_id] == None and online and RUNNING:
startedOnline[name_id] = timestamp
print(ts,name,'went online')
elif startedOnline[name_id] != None and ((not online) or not RUNNING):
ronline.append((name_id, startedOnline[name_id], timestamp))
st = time_string(startedOnline[name_id])
dt = time_string(timestamp - startedOnline[name_id], forString=True)
print(ts,name,'went offline, was online from',st,'to',tsnb,'for',dt)
startedOnline[name_id] = None
if startedPlaying[name_id] == None and playing and RUNNING:
startedPlaying[name_id] = timestamp
print(ts,name,'started playing')
elif startedPlaying[name_id] != None and ((not playing) or not RUNNING):
rplaying.append((name_id, startedPlaying[name_id], timestamp))
st = time_string(startedPlaying[name_id])
dt = time_string(timestamp - startedPlaying[name_id], forString=True)
print(ts,name,'stopped playing, was playing from',st,'to',tsnb,'for',dt)
startedPlaying[name_id] = None
cursor.executemany("""
INSERT INTO online_periods
VALUES(?, ?, ?)
""", ronline
)
cursor.executemany("""
INSERT INTO playing_periods
VALUES(?, ?, ?)
""", rplaying
)

except Exception as ex:
template = "An exception of type {0} occurred. Arguments:n{1!r}"
message = template.format(type(ex).__name__, ex.args)
print (message)
time.sleep(1)
st = time_string(start_timestamp)
et = time_string(end_timestamp)
dt = time_string(end_timestamp - start_timestamp, forString=True)
print('Recorded from',st,'to',et,'for',dt)
print('Writing recording periods to the database...')
cursor.executemany("""
INSERT INTO recording_periods
VALUES(?, ?, ?)
""", [(player, registeredWhen[player], end_timestamp) for player in registeredWhen]
)
print('Committing ...')
conn.commit()
print('Closing database connection...')
cursor.close()
conn.close()
print('Exit program...')

if __name__ == '__main__':
main()

会不会是终端?它不适合长时间跑步? 但我想使用终端。

由于我的程序在遇到错误时打印,但终端不打印任何错误消息, 我的猜测是它要么卡在数据库查询中,要么卡在 Lichess.org 的请求中。 我们的路由器/巫妖不时重新启动,数据库服务器不间断地启动,没有其他程序访问它(这可能会阻止程序查询(。这是一个在同一个Raspberry Pi上运行的MariaDB。

我不知道它是如何以及为什么卡住的,请告诉我你们这样做!

提前感谢!

我现在已经想通了,

这是因为 requests.get(( 中没有超时是默认值。 当路由器在 requests.get(( 运行时重新启动时,它将永远等待。 通过添加超时= 10来修复它。那个图书馆的创建者在想什么??

最新更新