python MySQLDB查询超时

mlu*_*bke 9 python mysql timeout

我试图在python MySQLDB中强制执行查询的时间限制.我有一种情况,我无法控制查询,但需要确保它们不会超过设定的时间限制.我已经尝试使用signal.SIGALRM中断执行的调用,但这似乎不起作用.信号被发送,但是在执行完成调用之后才会被捕获.

我写了一个测试用例来证明这种行为:

#!/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()'
Run Code Online (Sandbox Code Playgroud)

"SELECT SLEEP(10)"模拟慢速查询,但我确实看到了与实际慢速查询相同的行为.

结果:

START:   1254440686.69
TIMEOUT! 1254440696.69
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,它已经睡了10秒然后我得到了Timeout Exception.

问题:

  1. 为什么在执行完成之后我才收到信号?
  2. 是否有另一种可靠的方法来限制查询执行时间?

Ale*_*lli 8

@nosklo基于扭曲的解决方案优雅且可行,但如果你想避免对扭曲的依赖,那么任务仍然可行,例如:

import multiprocessing

def query_with_timeout(dbc, timeout, query, *a, **k):
  conn1, conn2 = multiprocessing.Pipe(False)
  subproc = multiprocessing.Process(target=do_query,
                                    args=(dbc, query, conn2)+a, 
                                    kwargs=k)
  subproc.start()
  subproc.join(timeout)
  if conn1.poll():
    return conn1.recv()
  subproc.terminate()
  raise TimeoutError("Query %r ran for >%r" % (query, timeout))

def do_query(dbc, query, conn, *a, **k):
  cu = dbc.cursor()
  cu.execute(query, *a, **k)
  return cu.fetchall()
Run Code Online (Sandbox Code Playgroud)