我想开发一个程序,它可以恢复使用sqlite3数据库的程序中的最后一个循环。
我有一个Raspberry Pi运行,其中源是Python,系统可能会出现电源故障并重启一段时间。
程序可以从启动启动,但可能很难回到程序的最后一个循环。让我们将print函数视为Python语法,每个语法延迟5秒,这意味着有4个不同的程序同步运行。
以下程序没有按预期工作,有人可以帮我解决这个难题吗?
import thread
import time
import sqlite3
conn = sqlite3.connect('testdatabase.db')
conn.isolation_level = None
c = conn.cursor()
c.execute("SELECT ID from LAST_STATE")
fetch=c.fetchone()
def morning_u():
conn = sqlite3.connect('testdatabase.db')
c = conn.cursor()
c.execute("UPDATE LAST_STATE SET ID=1")
conn.commit()
c.close()
conn.close()
def noon_u():
conn = sqlite3.connect('testdatabase.db')
c = conn.cursor()
c.execute("UPDATE LAST_STATE SET ID=2")
conn.commit()
c.close()
conn.close()
def afternoon_u():
conn = sqlite3.connect('testdatabase.db')
c = conn.cursor()
c.execute("UPDATE LAST_STATE SET ID=3")
conn.commit()
c.close()
conn.close()
def evening_u():
conn = sqlite3.connect('testdatabase.db')
c = conn.cursor()
c.execute("UPDATE LAST_STATE SET ID=4")
conn.commit()
c.close()
conn.close()
def morning():
print ("morning")
time.sleep(5)
return
def noon():
print ("noon")
time.sleep(5)
return
def afternoon():
print ("afternoon")
time.sleep(5)
def evening():
print ("evening")
time.sleep(5)
morning_u()
while True:
if fetch[0] is 1:
morning()
noon_u()
if fetch[0] is 2:
noon()
afternoon_u()
if fetch[0] is 3:
afternoon()
evening_u()
if fetch[0] is 4:
evening()
morning_u()
数据库信息
conn = sqlite3.connect('testdatabase.db')
conn.execute('''CREATE TABLE LAST_STATE
(ID INT PRIMARY KEY NOT NULL);''')
conn.execute("INSERT INTO LAST_STATE (ID) \
VALUES (1)");
根据评论编辑程序,请提出改进建议
import datetime
import time
import logging
import sqlite3
conn = sqlite3.connect('testdatabase.db')
conn.isolation_level = "IMMEDIATE"
c = conn.cursor()
c.execute("SELECT ID from LAST_STATE")
state=c.fetchone()
def morning_u():
c.execute("UPDATE LAST_STATE SET ID=1")
conn.commit()
def noon_u():
c.execute("UPDATE LAST_STATE SET ID=2")
conn.commit()
def afternoon_u():
c.execute("UPDATE LAST_STATE SET ID=3")
conn.commit()
def evening_u():
c.execute("UPDATE LAST_STATE SET ID=4")
conn.commit()
def morning():
print ("morning")
time.sleep(5)
def noon():
print ("noon")
time.sleep(5)
def afternoon():
print ("afternoon")
time.sleep(5)
def evening():
print ("evening")
time.sleep(5)
while True:
if state[0] is 1:
morning()
try:
noon_u()
except:
print ("error1")
if state[0] is 2:
noon()
try:
afternoon_u()
except:
print ("error2")
if state[0] is 3:
afternoon()
try:
evening_u()
except:
print ("error3")
if state[0] is 4:
evening()
try:
morning_u()
except:
print ("error4")
答案 0 :(得分:0)
我看到两个可能导致你的错误的直接问题。
首先,evening
调用morning_u
,但没有其他函数执行此操作,并且它对循环来说是多余的。
其次,你永远不会在循环中更新fetch
(这是一个不好的名字,考虑更像state
或time_of_day
)。循环将一遍又一遍地做同样的事情。
此外,您还要在每个函数调用时断开连接并重新连接到数据库。这是低效的,它可能会导致并发问题。可以更好地编写函数来接受现有的数据库连接。
最后,您有conn.isolation_level = None
自动提交,但您正在调用commit
。提交是一个无操作,但它可以欺骗读者认为你正在使用事务。通常,避免自动提交,并使用事务。事务对于并发非常重要。 SQLite defaults to odd implicit transactions这可能不会做你想要的,很难解开。我建议使用显式交易。对于最可预测的行为,可能immediate,但不是排他性的。设置conn.isolation_level = "IMMEDIATE"
。
设计明智,你说你想要一个崩溃恢复系统,但你正试图将它用作并发系统。这些是两个,主要是独家的东西。
崩溃恢复假设任何时候只有一个进程拥有该状态。它加载,它得到旧的状态,然后它快乐地假装它拥有状态并根据需要改变它。 没有其他人正在改变状态。它甚至可以通过桌面上的独占锁来保证这一点。
并发性假设许多进程都在更新状态。由于您正在构建状态机,因此对状态的每次更改都取决于现有状态。对状态的所有更改都必须是原子的:启动事务(即获取锁定),读取状态,更新状态和提交。状态的所有使用也必须是原子的:启动事务(即获取读锁以防止状态改变),读取状态,使用状态,结束事务。
对于崩溃恢复,您只需在程序开始时读取一次状态。您只需在更改时编写它。
对于并发性,您必须在程序开始时以及任何想要使用它的状态下读取状态。当您使用它时,您必须获得共享锁,以确保它在此期间不会发生变化。
您拥有崩溃恢复所需的代码,您所缺少的只是确保状态更改函数更新状态(即fetch[0]
)。你没有并发代码,但你不需要它。