Python threading test not working
EDIT
I solved the issue by forking the process instead of using threads. From the comments and links in the comments, I don't think threading is the right move here.
Thanks everyone for your assistance.
FINISHED EDIT
I haven't done much with threading before. I've created a few simple example "Hello World" scripts but nothing that actually did any work.
To help me grasp it, I wrote a simple script using the binaries from Nagios to query services like HTTP. Thi开发者_运维技巧s script works although with a timeout of 1 second if I have 10 services that timeout, the script will take over 10 seconds long.
What I want to do is run all checks in parallel to each other. This should reduce the time it takes to complete.
I'm currently getting segfaults but not all the time. Strangely at the point where I check the host in the processCheck function, I can printout all hosts. Just after checking the host though, the hosts variable only prints one or two of the hosts in the set. I have a feeling it's a namespace issue but I'm not sure how to resolve.
I've posted the entire code here sans the MySQL db but a result from he service_list view looks like.
Any assistance is greatly appreciated.
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()
The MySQL DB driver isn't thread safe. You're using the same cursor concurrently from all threads.
Try creating a new connection in each thread, or create a pool of connections that the threads can use (e.g. keep them in a Queue
, each thread get
s a connection, and put
s it pack when it's done).
You should be constructing and populating your queue first. When the entire queue is constructed and populated, then you should construct a number of threads which then, each in a loop, polls the queue and processes an item on the queue.
You realize Python doesn't do true multi-threading as you would expect on a multi-core processor:
See Here And Here
Don't expect those 10 things to take 1 second each. Besides, even in true multi-threading there is a little overhead associated with the threads. I'd like to add that this isn't a slur against Python.
精彩评论