Python脚本停止,没有错误给出

时间:2017-06-01 11:13:37

标签: python sql flask firebird sensor

我有一个需要一直运行的python脚本。有时它可以运行一天,有时它只运行一个小时。

    import RPi.GPIO as GPIO
import fdb
import re

con = fdb.connect(dsn='10.100.2.213/3050:/home/trainee2/Desktop/sms', user='sysdba', password='trainee') #connect to database
cur = con.cursor() #initialize cursor 

pinnen = [21,20,25,24,23,18,26,19,13,6,27,17] #these are the GPIO pins we use,  they are the same on all PI's! We need them in this sequence.
status = [0] * 12 #this is an empty array were we'll safe the status of each pin
ids = []
controlepin = [2] * 12 #this array will be the same as the status array, only one step behind, we have this array so we can know where a difference is made so we can send it
GPIO.setmode(GPIO.BCM) #Initialize GPIO

getPersonIDs()  #get the ids we need


for p in range(0,12):
    GPIO.setup(pinnen[p],GPIO.IN) #setup all the pins to read out data

while True: #this will repeat endlessly
    for e in range(0,12):
        if ids[e]: #if there is a value in the ids (this is only neccesary for PI 3 when there are not enough users
            status[e] = GPIO.input(pinnen[e]) #get the status of the GPIO. 0 is dark, 1 is light
            if (status[e] != controlepin[e]): #if there are changes 
                id = ids[e]
                if id != '': #if the id is not empty
                    if status[e] == 1: #if there is no cell phone present
                        cur.execute("INSERT INTO T_ENTRIES (F_US_ID, F_EN_STATE) values (? ,0)",(id)) #SEND 0, carefull! Status 0 sends 1, status 1 sends 0 to let it make sense in the database!!
                    else :
                        cur.execute("INSERT INTO T_ENTRIES (F_US_ID, F_EN_STATE) values (? ,1)",(id))

                con.commit() #commit your query
                controlepin[e] = status[e]  #safe the changes so we woulnd't spam our database  
    time.sleep(1) #sleep for one second, otherwise script will crash cause of while true


def getPersonIDs(): #here we get the IDS 
    cur.execute("SELECT first 12 A.F_US_ID FROM T_RACK_SLOTS a order by F_RS_ID;") #here is where the code changes for each pi
    for (ID) in cur:
        ids.append(ID) #append all the ids to the array

该脚本用于手机架,通过LDR我可以看到手机是否存在,然后我将该数据发送到Firebird数据库。脚本正在运行我的Raspberry PI。

如果连接丢失几秒钟,脚本会停止吗?有没有办法确保他们的查询总是发送?

1 个答案:

答案 0 :(得分:0)

  

如果连接丢失了几秒钟,脚本会停止吗?

更重要的是,脚本IS会针对每个Firebird命令停止,包括con.commit(),并且只有当Firebird处理命令/查询时它才会继续。

所以,我不太了解Python库,我仍然会给你一些建议。

1)尽可能多地使用参数和prepared查询。

 if status[e] == 1: #if there is no cell phone present
                        cur.execute("INSERT INTO T_ENTRIES (F_US_ID, F_EN_STATE) values (? ,0)",(id)) #SEND 0, carefull! Status 0 sends 1, status 1 sends 0 to let it make sense in the database!!
                    else :
                        cur.execute("INSERT INTO T_ENTRIES (F_US_ID, F_EN_STATE) values (? ,1)",(id))

这不是最好的主意。您强制Firebird引擎解析查询文本并一次又一次地构建查询。浪费时间和资源。

正确的方法是进行INSERT INTO T_ENTRIES (F_US_ID, F_EN_STATE) values (?,?)查询,然后进行prepare查询,然后运行已准备好的查询来更改参数。你只需要在循环之前准备一次,然后多次运行它。

当然,我不知道如何在Python库中查询prepare,但我认为你会找到这些例子。

2)不要使用SQL服务器来保存您获得的每个数据元素。这是一个众所周知的不良行为,十年前曾被提出过。特别是懒惰的版本引擎Interbase / Firebird就是。

问题是,Firebird每次发表声明都会检查一些内部统计数据,有时会决定做家务的时间。

例如,您的select语句类似于garbage collection。 Firebird可能会停止扫描所有表,找到孤立的过时版本的行并清除它们。例如,你的insert语句类似于索引重新创建:如果Firebird认为索引的B-Tree过于片面,它会丢弃它,并构建一个新的平衡树,读出整个表(是的,阅读表格可能会在树木娱乐活动中引发GC。)

更重要的是,让我们远离Firebird的具体细节 - 你会做什么ig Firebird崩溃?只是崩溃,这是一个程序,就像每个程序一样,它可能有bug。或者例如,你的磁盘空间不足,Firebird就不能再在数据库中插入任何内容了 - 那么你的硬件传感器数据会在哪里结束?不知道它会丢失吗?

http://www.translate.ru - 这个通常比Google或Microsoft翻译好,特别是如果你将词汇表设置为计算机。

请参阅http://www.ibase.ru/dontdoit/上的#7 - "请勿在每一行"之后发出提交。在https://www.ibase.ru/45-ways-to-improve-firebird-performance-russian/处的#24建议提交大约一千行的数据包作为许多事务和过多未提交数据之间的最佳点。还要检查最后一个链接的#9,#10,#16和#17和#44。

我认为软件综合体的整体结构必须分为两种服务。

  1. 从硬件传感器查询数据并将其保存为普通的愚蠢二进制平面文件。由于此文件是最简单的格式,因此性能和可靠性最大化。
  2. 准备好二进制文件,并以批量插入模式将它们插入SQL数据库。
  3. 因此,例如,您将阈值设置为10240行。

    1. 服务#1创建文件" Phones_1_Processing"使用BINARY明确定义的格式。它还创建并打开了Phones_2_Processing"文件,但保持0长度。然后它继续在" Phones_1_Processing"中添加行。一阵子。在每一行或每100行之后,它也可能flush OS文件缓冲区,或者在可靠性和性能之间取得最佳平衡的东西。
    2. 当满足阈值时,服务#1切换到将输入的数据单元记录到已经创建并打开的“Phones_2_Processing"文件。它可以立即完成,在程序中更改一个file handler类型变量。
    3. 然后服务#1关闭并重命名" Phones_1_Processing"进入"" Phones_1_Complete"。
    4. 然后服务#1创建新的空文件" Phones_3_Processing"并保持打开,零长度。现在又回到了状态" 1" - 准备好在当前文件结束时立即将其录制切换到新文件。
    5. 这里的关键点是服务应该只进行最简单和最快速的操作。由于任何随机延迟都意味着您的实时生成的数据会丢失并且永远无法恢复。顺便说一句,如何在Python中禁用垃圾收集,因此它不会“停止世界”#34;突然?好的,半开玩笑。但问题仍然存在。 GC是系统的随机非确定性故障,与常规的非缓冲硬件数据采集非常兼容。使用大多数简单=可预测的服务可以更好地完成对非缓冲数据的主要采集,而GC是一个很好的全局优化,但价格往往会导致突然的本地无服务峰值。

      因为这一切都发生在服务#1和另一个服务器上。

      1. 服务#2会持续监控用于保存主数据的文件夹中的数据更改。它订阅"某些文件已重命名"事件并忽略其他人。使用哪种服务?问Linux大师。 iNotify,dNotify,FAM,Gamin,任何适合的类型。
      2. 当服务#2被唤醒"文件被重命名并且xxxx是新名称"它检查新文件名是否以" _Complete"结尾。如果没有 - 那那就是一个虚假的事件。
      3. 当活动是针对新的"电话_...._完成"文件,然后是"批量插入"它进入Firebird。 Google for" Firebird批量插入",例如http://www.firebirdfaq.org/faq209/
      4. 服务#2重命名" Phone_1_Complete"进入" Phone_1_Inserting",所以数据包的状态是持久的(作为文件名)。
      5. 服务#2将此文件作为EXTERNAL TABLE
      6. 附加到Firebird数据库中
      7. 服务#2继续进行批量插入,如上所述。取消激活索引,它会打开一个无自动撤消事务,并不断将外部表中的行抽入目标表。如果服务或服务器在此崩溃 - 您具有一致的状态:事务被回滚,文件名显示它仍处于待处理状态。
      8. 当抽取所有行时 - 坦率地说,如果Python可以使用二进制文件,那么它将是单个INSERT-FROM-SELECT, - 您提交事务,删除External Table(从文件中分离firebird) ),然后重命名" Phone_1_Inserting"将文件导入" Phone_2_Done" (保持其更改状态)然后将其删除。
      9. 然后服务#2查看是否有新的" _Complete"已经准备好在文件夹中的文件,如果没有,它会进入第1步 - 睡眠直到FAM事件唤醒它
      10. 总而言之,你应该解开你的服务。

        https://en.wikipedia.org/wiki/Coupling_%28computer_programming%29

        服务的主要责任在于准备好获取和保存数据流,而另一项服务的责任是将保存的数据转移到SQL数据库中以便于处理,并且它不是很大问题,如果它有时会延迟几秒钟,只要它最终不会丢失数据。