Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python用户在无限循环内输入太慢,容易混淆_Python_Python 2.7_Sqlite_Raspberry Pi - Fatal编程技术网

Python用户在无限循环内输入太慢,容易混淆

Python用户在无限循环内输入太慢,容易混淆,python,python-2.7,sqlite,raspberry-pi,Python,Python 2.7,Sqlite,Raspberry Pi,我有一个运行在Raspberry Pi上的Python脚本,它等待用户输入,并将输入记录在SQLite数据库中: #!/usr/bin/env python import logging import db while True: barcode = raw_input("Scan ISBN: ") if ( len(barcode) > 1 ): logging.info("Recording scanned ISBN: " + barcode)

我有一个运行在Raspberry Pi上的Python脚本,它等待用户输入,并将输入记录在SQLite数据库中:

#!/usr/bin/env python

import logging
import db

while True:
    barcode = raw_input("Scan ISBN: ")
    if ( len(barcode) > 1 ):
        logging.info("Recording scanned ISBN: " + barcode)
        print "Recording scanned ISBN: " + barcode
        db.recordScan(barcode, 1)
db.recordScan()
方法如下所示:

# Adds an item to queue
def recordScan(isbn, shop_id):
    insert = "INSERT INTO scans ( isbn, shop_id ) VALUES ( ?, ? )"
    conn = connect()
    conn.cursor().execute(insert, [isbn, shop_id])
    conn.commit()
    conn.close()
Scan ISBN: 9780465031467
Recording scanned ISBN: 9780465031467
Scan ISBN: 9780141014593
Recording scanned ISBN: 9780141014593
Scan ISBN: 
(注意:如果您想了解我如何连接到数据库等,可以在上查看整个代码repo)

我的问题是,使用USB条形码扫描仪(实际上只是一个键盘输入,发送一系列击键,然后按
Enter
键)很容易以如此快的速度输入,以至于命令行似乎变得“混乱”

例如,比较以下结果…

当您放慢速度时,脚本工作正常,命令看起来整洁,如下所示:

# Adds an item to queue
def recordScan(isbn, shop_id):
    insert = "INSERT INTO scans ( isbn, shop_id ) VALUES ( ?, ? )"
    conn = connect()
    conn.cursor().execute(insert, [isbn, shop_id])
    conn.commit()
    conn.close()
Scan ISBN: 9780465031467
Recording scanned ISBN: 9780465031467
Scan ISBN: 9780141014593
Recording scanned ISBN: 9780141014593
Scan ISBN: 
但是,当你使劲敲击并快速前进时,输入提示会自动超前,脚本打印的消息会写在输入提示的顶部:

Recording scanned ISBN: 9780141014593
9780141014593
9780141014593
9780465031467
Recording scanned ISBN: 9780141014593
Scan ISBN: Recording scanned ISBN: 9780141014593
Scan ISBN: Recording scanned ISBN: 9780141014593
Scan ISBN: Recording scanned ISBN: 9780465031467
Scan ISBN: 9780571273188
9780141014593
它有时会无限期地挂在那个位置,我不知道它在做什么,但你可以用另一个输入再次唤醒它,它会正常运行,尽管挂在上面的输入没有被记录下来,这很糟糕,因为它使整个系统不可靠


我的问题是:这是我不得不接受的必然性吗?我是否总是能够通过连续输入过多的信息来超越低功耗的Raspberry Pi,或者是否有更快的方法来实现这一点?我是否可以将数据库写入操作推送到另一个线程或类似的线程?原谅我的无知,我正在学习

不要从用户输入生成SQL字符串。永远

始终使用参数化查询

# Adds an item to queue
def recordScan(isbn, shop_id):
    insert = "INSERT INTO scans ( isbn, shop_id ) VALUES ( ?, ? )"
    conn = connect()
    conn.cursor().execute(insert, [isbn, shop_id])
    conn.commit()
    conn.close()

请阅读,至少是页面的上半部分,他们在那里解释了这种方法。

您似乎每次都在打开和关闭数据库。这显然会增加巨大的开销,尤其是当你在“敲打”它时。
开始时连接数据库一次,退出后关闭。
在此期间,只需执行
insert
update
delete
语句

编辑:
为此,我将
db.py
重命名为
barcode1.py
,以便进行适当的编辑。 将
listen.py
更改如下:

#!/usr/bin/env python

import logging
import barcode1
DB_FILE_NAME = "scan-queue.db"
my_db = barcode1.sqlite3.connect(DB_FILE_NAME)
my_cursor = my_db.cursor()

def InsertScan(isbn, shop_id):
    insert = "INSERT INTO scans ( isbn, shop_id ) VALUES ( ?, ? )"
    my_cursor.execute(insert, [isbn, shop_id])
    my_db.commit()

while True:
    barcode = raw_input("Scan ISBN: ")
    if ( len(barcode) > 1 ):
        logging.info("Recording scanned ISBN: " + barcode)
        print "Recording scanned ISBN: " + barcode
        InsertScan(barcode, 1)
my_db.close()
出于您的目的,将对“条形码1”的引用替换为“db”
正如您所看到的,这里所发生的一切是,添加了一个单独的函数来执行写入操作,并且只执行写入操作。
很明显,这是一个快速的模型,可以得到极大的改进,事实上,我已经将其重写为一个脚本。这是一个典型的例子,在这个例子中,试图编写面向对象的代码时,您最终会自食其果。
实际上,您可以不使用该函数,只在
while
语句中包含
insert
代码

锁定: 从sqlite3文档:

 sqlite3.connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri])
打开到SQLite数据库文件数据库的连接。您可以使用“:memory:”打开与驻留在RAM中而不是磁盘上的数据库的数据库连接


当一个数据库被多个连接访问,并且其中一个进程修改该数据库时,SQLite数据库将被锁定,直到提交该事务为止。timeout参数指定在引发异常之前,连接应等待锁消失的时间。超时参数的默认值为5.0(5秒)。

根据用户@tomalak、@rolf of saxony和@hevlastka的有用建议进行了大量实验后,我的结论是是的,这是我不得不忍受的必然性。

即使您通过删除数据库写入过程并使其成为一个简单的parrot脚本,只重复返回输入(请参阅),将示例简化为基本内容,但仍然可以快速扫描项目,从而忽略/跳过/忽略输入。覆盆子皮根本跟不上


因此,我现在的方法是添加一个音频反馈功能,如嘟嘟声,以指示用户设备何时准备好接收下一个输入。这是一条我不想走的路线,但我的代码似乎是最有效的,我们仍然能够达到极限。责任在于用户不能以极快的速度前进,我们能做的最好的事情就是给他们良好的反馈

除了我在第一次回答中提出的问题外,还有另一个影响更新速度的问题,即
提交

您会发现,如果成批提交
commit
,速度会成倍提高。调整日志记录,它会再次向上移动。
在PI 3上工作时,我在10秒内模拟了5000次更新,日志打开时为10秒,日志关闭时为0.43秒。
如果您更改代码以将条形码存储在列表中,然后批量启动数据库更新,那么您的代码将在Raspberry Pi上工作

请参阅下面的测试代码:

#!/usr/bin/env python
import sqlite3
import time
DB_FILE_NAME = "scan-queue.db"
my_db = sqlite3.connect(DB_FILE_NAME)
my_cursor = my_db.cursor()
my_cursor.execute('CREATE TABLE if not exists scans(id INTEGER PRIMARY KEY AUTOINCREMENT,isbn TEXT NOT NULL,shop_id INT NOT NULL)')   
my_db.commit()
#This line turns off journaling, passing off the writes to the OS
# No rollbacks are available and corruption can occur if the machine has an issue
# but you're not NASA
my_cursor.execute("PRAGMA synchronous = OFF") #Can increase speed 20 fold
def InsertScan(isbn, shop_id):
    insert = "INSERT INTO scans ( isbn, shop_id ) VALUES ( ?, ? )"
    my_cursor.execute(insert, [isbn, shop_id])

tot_t = time.time() #Time entire run
shop_id = 1
barcode = 11111111111111
batch=[]
while shop_id < 5000:
    #barcode = raw_input("Scan ISBN: ")
    batch_cnt = 0
    while batch_cnt < 100:
        shop_id +=1
        barcode +=1
        batch_cnt +=1
        print "Recording scanned ISBN: ", barcode, shop_id
        batch.append((barcode,shop_id))
    print "Saving", str(len(batch)), "scanned ISBN's"
    t = time.time() #Time batch update
    for i in batch:
        InsertScan(i[0],i[1])
    batch=[]
    my_db.commit()
    t2 = time.time() - t
    print "Secs =", t2 #Print update time in seconds
print "Saving", str(len(batch)), "scanned ISBN's"
for i in batch: #Final update (just in case) or when program is quit
    InsertScan(i[0],i[1])
my_db.commit()
x = my_cursor.execute("select count(*) from scans")
tot_t2 = time.time() - tot_t
print "5000 Updates in ", tot_t2 #Print update time in seconds
for i in x:
    print i,"Total rows in scans table" #Print total of records in table
my_db.close() 
#/usr/bin/env python
导入sqlite3
导入时间
DB\u FILE\u NAME=“scan queue.DB”
my_db=sqlite3.connect(db_文件名)
my_cursor=my_db.cursor()
my_cursor.execute('CREATE TABLE if not exists scans(id INTEGER主键自动递增,isbn TEXT not NULL,shop_id INT not NULL)'
my_db.commit()
#这一行关闭日志记录,将写操作传递到操作系统
#没有可用的回滚,如果计算机出现问题,可能会发生损坏
#但你不是NASA
my_cursor.execute(“PRAGMA synchronous=OFF”)#可以将速度提高20倍
def插入扫描(isbn,车间id):
insert=“插入扫描(isbn,车间id)值(?,)”
my_cursor.execute(插入[isbn,店铺id])
tot_t=time.time()#整个运行的时间
车间标识=1
条形码=11111111
批次=[]
当店铺id<5000时:
#条形码=原始输入(“扫描ISBN:”)
批次=0
当批次小于100时:
店铺id+=1
条码+=1
批次cnt+=1
P