【发布时间】:2011-12-31 22:24:12
【问题描述】:
我已经用 Python 开发了一个基本的代理测试器。代理 IP 和端口,以及它们的 date_of_last_test(例如 31/12/2011 10:10:10)和 result_of_last_test(OK 或 KO)存储在单个 SQLite 表中。 (我意识到我可以存储更多关于测试结果的详细信息并保留历史/统计信息,但这个简单的模型适合我的需要)。
这是测试器主循环的简化代码,我在其中循环代理并更新它们的状态:
while True:
# STEP 1: select
myCursor.execute("SELECT * from proxy ORDER BY date_of_last_test ASC;")
row = myCursor.fetchone()
# STEP 2: update
if isProxyWorking(row['ip'], row['port']): # this test can last a few seconds
updateRow(row['ip'], row['port'], 'OK')
else:
updateRow(row['ip'], row['port'], 'KO')
我的代码在作为单个进程运行时运行良好。现在,我希望能够运行程序的多个进程,使用相同的 SQLite 数据库文件。 当前代码的问题是缺少一种锁定机制,该机制会阻止多个进程测试同一个代理。
在 STEP 1 / SELECT 时间锁定行的最干净的方法是什么,以便下一个执行 SELECT 的进程获得下一行?
换句话说,我想避免以下情况:
假设现在是晚上 10 点,数据库包含 2 个代理:
代理 A 最后一次测试是晚上 8 点,代理 B 测试是晚上 9 点。
我启动测试器的两个进程来更新它们的状态:
- 10:00 - 进程 1 获取“最旧”代理来测试它:
A - 10:01 -
进程 2 获取“最旧”的代理来测试它:!!!
A!!! (在这里我会 像过程 2 一样获取代理B因为A已经在测试中 - 虽然尚未在 db 中更新) - 10:10 - 进程 1 对
A的测试是 结束,其状态在 DB 中更新 - 10:11 - 进程 2 对
A的测试是 结束,它的状态在 DB 中被更新(!!! AGAIN !!!)
在这种情况下没有实际的错误/异常,但我想避免浪费时间。
【问题讨论】:
-
我认为理解代码比 True/False 更容易:P
-
我有类似的问题,并决定不仅选择最旧的记录,而且选择最旧的记录,其中 id % NUM_OF_THREADS。通过这种方式,我们在工作线程之间划分所有记录,因此不会发生冲突。我知道这会产生一些问题,例如如果某些工作线程无事可做,但统计上可以。 (顺便说一句。KO & OK 不好,因为它很容易出错。这不是防御性编程。但是防御性编程通常很无聊。;))