我试图在python MySQLDB中对查询强制执行时间限制。我有一种情况,我无法控制查询,但需要确保它们不会超过设置的时间限制。我尝试使用signal.SIGALRM中断调用execute,但这似乎不起作用。信号被发送,但直到execute调用完成后才被捕获。
我写了一个测试用例来证明这种行为:
#!/usr/local/bin/python2.6
import time
import signal
from somewhere import get_dbc
class Timeout(Exception):
""" Time Exceded """
def _alarm_handler(*args):
raise Timeout
dbc = get_dbc()
signal.signal(signal.SIGALRM, _alarm_handler)
signal.alarm(1)
try:
print "START: ", time.time()
dbc.execute("SELECT SLEEP(10)")
except Timeout:
print "TIMEOUT!", time.time()'
字符串
“SELECT SLEEP(10)”模拟了一个慢查询,但我确实看到了一个实际的慢查询的相同行为。
结果:
START: 1254440686.69
TIMEOUT! 1254440696.69
型
正如你所看到的,它休眠了10秒钟,然后我得到了一个异常。
问题:
1.为什么我在执行完成后才收到信号?
1.是否有其他可靠的方法来限制查询执行时间?
7条答案
按热度按时间qlckcl4x1#
@nosklo的基于twisted的解决方案是优雅和可行的,但是如果你想避免对twisted的依赖,这个任务仍然是可行的,例如:
字符串
b1payxdu2#
使用adbapi。它允许你异步地进行数据库调用。
字符串
fcipmucu3#
我试过使用signal.SIGALRM中断execute调用,但似乎不起作用。信号被发送,但直到execute调用完成后才被捕获。
mysql库在内部处理中断的系统调用,因此在API调用完成之前,您不会看到SIGALRM的副作用(除非杀死当前线程或进程)
您可以尝试修补MySQL-Python并使用MYSQL_OPT_READ_TIMEOUT选项(在mysql 5.0.25中添加)
mpgws1up4#
为什么我在执行完成后才收到信号?
查询通过C函数执行,该函数阻止Python VM执行,直到它返回。
是否有其他可靠的方法来限制查询执行时间?
这是(IMO)一个非常丑陋的解决方案,但它确实有效。您可以在单独的进程中运行查询(通过
fork()
或multiprocessing
module)。在主进程中运行警报计时器,当您收到它时,发送SIGINT
或SIGKILL
到子进程。如果您使用multiprocessing
,您可以使用Process.terminate()
方法。mbjcgjjk5#
通用注解
我最近遇到了同样的问题,我必须满足几个条件:
我们有以下类布局(* 不幸的是,我不能张贴真实的来源 *):
字符串
为每个模型创建了多个线程。
Python 3.2解决方案
在我们的应用程序中,* 一个模型=一个数据库 。所以我为每个模型创建了“ 服务连接 *”(这样我们就可以并行连接执行
KILL
)。因此,如果创建了一个FirstDatabaseModel
示例,则创建了2个数据库连接;如果创建了5个示例,则只使用了6个连接:型
现在我们需要一个杀手
型
connection.execute
=创建游标,执行,关闭游标。*使用
threading.Lock
使杀手级线程安全:型
最后使用
threading.Timer
添加定时执行方法:型
isr3a4wc6#
在mysql中,可以设置执行超时。
字符串
如果
timeout_in_milliseconds
小于10秒,则SLEEP
查询应缩短。lxkprmvk7#
为什么我在执行完成后才收到信号?
等待网络I/O的进程处于不可中断状态(UNIX的东西,与Python或MySQL无关)。它在系统调用完成后获得信号(可能是
EINTR
错误代码,尽管我不确定)。是否有其他可靠的方法来限制查询执行时间?
我认为这通常是由外部工具完成的,比如
mkill
,它监视MySQL长时间运行的查询并杀死它们。