python中的正确线程

时间:2013-02-12 19:46:42

标签: python multithreading mq

我正在编写家庭自动化帮助程序 - 它们基本上是类似守护程序的小型python应用程序。他们可以作为一个单独的进程运行每个进程,但是因为我将决定我将建立一个小的调度程序,它将在自己的线程中生成每个守护进程,并且能够在将来一个线程死掉。

这就是它的样子(使用两个类):

from daemons import mosquitto_daemon, gtalk_daemon
from threading import Thread

print('Starting daemons')
mq_client = mosquitto_daemon.Client()
gt_client = gtalk_daemon.Client()

print('Starting MQ')
mq = Thread(target=mq_client.run)
mq.start()

print('Starting GT')
gt = Thread(target=gt_client.run)
gt.start()

while mq.isAlive() and gt.isAlive():
    pass
print('something died')

问题是MQ守护进程(moquitto)可以正常工作,我可以直接运行它:

mq_client = mosquitto_daemon.Client()
mq_client.run()

它将开始并在那里听取所有涉及相关主题的消息 - 正是我正在寻找的。

但是,在调度程序中运行会使其行为奇怪 - 它将收到一条消息,然后停止执行,但报告该线程仍处于活动状态。鉴于它没有线程woodoo工作正常我假设我在调度员做错了。

我引用MQ客户端代码以防万一:

import mosquitto
import config
import sys
import logging


class Client():
    mc = None

    def __init__(self):
        logging.basicConfig(format=u'%(filename)s:%(lineno)d %(levelname)-8s [%(asctime)s]  %(message)s', level=logging.DEBUG)
        logging.debug('Class initialization...')
        if not Client.mc:
            logging.info('Creating an instance of MQ client...')
            try:
                Client.mc = mosquitto.Mosquitto(config.DEVICE_NAME)
                Client.mc.connect(host=config.MQ_BROKER_ADDRESS)
                logging.debug('Successfully created MQ client...')
                logging.debug('Subscribing to topics...')
                for topic in config.MQ_TOPICS:
                    result, some_number = Client.mc.subscribe(topic, 0)
                    if result == 0:
                        logging.debug('Subscription to topic "%s" successful' % topic)
                    else:
                        logging.error('Failed to subscribe to topic "%s": %s' % (topic, result))
                logging.debug('Settings up callbacks...')
                self.mc.on_message = self.on_message
                logging.info('Finished initialization')
            except Exception as e:
                logging.critical('Failed to complete creating MQ client: %s' % e.message)
                self.mc = None
        else:
            logging.critical('Instance of MQ Client exists - passing...')
            sys.exit(status=1)

    def run(self):
        self.mc.loop_forever()

    def on_message(self, mosq, obj, msg):
        print('meesage!!111')
        logging.info('Message received on topic %s: %s' % (msg.topic, msg.payload))

2 个答案:

答案 0 :(得分:2)

您正在传递Thread另一个类实例的run方法......它真的不知道如何处理它。

threading.Thread可以通过两种通用方式使用:生成Thread包装的独立函数,或者作为具有run方法的类的基类。 在您的情况下,由于您的Client类具有run方法,因此基本类似乎是可行的方法。

替换MQ课程中的以下内容,它应该有效:

from threading import Thread

class Client(Thread):
    mc = None

    def __init__(self):
        Thread.__init__(self) # initialize the Thread instance
        ...
    ...

    def stop(self):
        # some sort of command to stop mc
        self.mc.stop() # not sure what the actual command is, if one exists at all...

然后在调用它时,不使用Thread

执行此操作
mq_client = mosquitto_daemon.Client()
mq_client.start() 

print 'Print this line to be sure we get here after starting the thread loop...'

答案 1 :(得分:1)

需要考虑的几件事情:

  1. zeromq讨厌在1个线程中初始化并在另一个线程中运行。您可以按照建议将Client()重写为Thread,或者编写自己的函数来创建Client并在线程中运行该函数。

  2. Client()有一个类级别变量mc。我假设mosquitto_daemon和gtalk_daemon都使用相同的客户端,因此它们争用Client.mc获胜。

  3. "而mq.isAlive()和gt.isAlive():传递"会吃掉整个处理器,因为它只是在不睡觉的情况下反复进行轮询。考虑到python只是准线程(全局解释器锁(GIL)只允许一次运行1个线程),这将使你的守护进程停止运行"。

  4. 同时考虑到GIL,orignal守护程序的实现可能会更好。