Python线程测试无效

1 投票
3 回答
1352 浏览
提问于 2025-04-15 15:50

编辑

我通过创建进程来解决这个问题,而不是使用线程。从评论和评论中的链接来看,我觉得在这里使用线程并不是正确的选择。

感谢大家的帮助。

编辑完毕

我之前对线程的了解不多。我只写过几个简单的“你好,世界”脚本,但没有做过实际的工作。

为了帮助我理解线程,我写了一个简单的脚本,使用Nagios的二进制文件来查询像HTTP这样的服务。这个脚本可以工作,但如果我有10个服务超时,脚本会因为每个服务超时1秒而总共耗时超过10秒。

我想要做的是让所有检查同时进行,这样可以减少完成所需的时间。

目前我遇到了段错误(segfault),但并不是每次都会出现。奇怪的是,在processCheck函数中检查主机时,我可以打印出所有主机。但在检查主机之后,hosts变量只打印出一两个主机。我觉得这可能是命名空间的问题,但不太确定怎么解决。

我在这里发布了整个代码,除了MySQL数据库的部分,但服务列表视图的结果看起来是这样的。

任何帮助都非常感谢。

6543L, 'moretesting.com', 'smtp')
(6543L, 'moretesting.com', 'ping')
(6543L, 'moretesting.com', 'http')


from commands import getstatusoutput
import MySQLdb
import threading
import Queue
import time

def checkHost(x, service):
    command = {}
    command['http'] = './plugins/check_http -t 1 -H '
    command['smtp'] = './plugins/check_smtp -t 1 -H '

    cmd = command[service]
    cmd += x
    retval = getstatusoutput(cmd)
    if retval[0] == 0:
        return 0
    else: 
        return retval[1]

def fetchHosts():
    hostList = []
    cur.execute('SELECT veid, hostname, service from service_list')
    for row in cur.fetchall():
        hostList.append(row)
    return hostList

def insertFailure(veid, hostname, service, error):
    query = 'INSERT INTO failures (veid, hostname, service, error) '
    query += "VALUES ('%s', '%s', '%s', '%s')" % (veid, hostname, service, error)
    cur.execute(query)
    cur.execute('COMMIT')


def processCheck(host):
    #If I print the host tuple here I get all hosts/services
    retval = checkHost(host[1], host[2])
    #If I print the host tuple here, I get one host maybe two
    if retval != 0:
        try:
            insertFailure(host[0], host[1], host[2], retval)
        except:
            pass
    else:
        try:
            #if service is back up, remove old failure entry
            query = "DELETE FROM failures WHERE veid='%s' AND service='%s' AND hostname='%s'" % (host[0], host[2], host[1])
            cur.execute(query)
            cur.execute('COMMIT')
        except:
            pass
    return 0

class ThreadClass(threading.Thread):

    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.queue = queue

    def run(self):
        processCheck(queue.get())
        time.sleep(1)

def main():
    for host in fetchHosts():
        queue.put(host)
        t = ThreadClass(queue)
        t.setDaemon(True)
        t.start()

if __name__ == '__main__':
    conn = MySQLdb.connect('localhost', 'root', '', 'testing')
    cur = conn.cursor()
    queue = Queue.Queue()
    main()
    conn.close()

3 个回答

0

你会发现,Python并不像你想象的那样在多核处理器上实现真正的多线程。

点击这里了解更多 再点击这里

不要指望那10个任务每个都只花1秒钟。而且,即使是在真正的多线程中,线程之间也会有一些额外的开销。我想补充的是,这并不是在贬低Python。

0

你应该先建立并填充你的队列。等队列完全建立好并且里面有东西后,再创建几个线程。每个线程会在一个循环中,不断地检查队列,并处理队列里的一个项目。

8

MySQL数据库的驱动程序不支持多线程安全。也就是说,你在多个线程中同时使用了同一个游标,这样会出问题。

你可以尝试在每个线程中创建一个新的连接,或者建立一个连接池,让线程们可以共享使用这些连接(比如把连接放在一个Queue里,每个线程get一个连接,使用完后再put回去)。

撰写回答