从python中的另一个线程唤醒睡眠中的特定线程

时间:2014-08-27 02:12:32

标签: python multithreading sleep wait

我已经在这个人身上追了好几天了,而且我疯了。我是一个非常业余的人,对蟒蛇来说是全新的,所以请原谅我的愚蠢。

我的主线程反复检查数据库中的条目,然后为它在数据库中找到的每个新条目启动线程。

它启动的线程基本上会轮询数据库中的某个值,如果它没有找到该值,它会做一些事情,然后它会休眠60秒并重新开始。

启动线程的简化非代码

while True:
    stop = _Get_a_Value_From_Database_for_Exit() #..... a call to DBMS 
    If stop = 0:
        Do_stuff()
        time.sleep(60)
    else:
        break

在任何给定时间都可能有许多这些线程在运行。我想要做的是让主线程检查数据库中的另一个特定值的位置,然后可以在上面的示例中中断已启动的特定线程中的睡眠。目标是退出上面列出的特定线程,而不必等待睡眠持续时间的剩余时间。所有这些线程都可以由共享的数据库ID引用。我已经看到对 event.wait() event.set() 的引用一直试图找出如何替换 time.sleep() ,但我不知道如何使用它来唤醒特定的线程而不是所有线程。

这是我无知的地方:有没有办法可以为event.wait创建基于数据库id的东西(在启动的线程中像12345.wait(60)一样12345.set()在主线程中(所有动态都基于不断变化的数据库 id )。

感谢您的帮助!!

2 个答案:

答案 0 :(得分:2)

项目有点复杂,这是我的版本。

  • 扫描数据库文件/tmp/db.dat,预先填写两个单词

  • 经理:为每个单词创建一个主题;默认是“威士忌”线程和“糖浆”线程

  • 如果一个单词以_stop结尾,如syrup_stop,则通过设置其停止事件告诉该主题死亡

  • 每个线程扫描数据库文件,如果它看到单词stop则退出。如果设置了停止事件,它也会退出。

  • 请注意,如果Manager线程设置了worker的stop_event,则worker将立即退出。每个线程都做了一些事情,但大部分时间花在stop_ev.wait()调用上。因此,当事件确定时,它不必坐在那里,它可以立即退出。

服务器很有趣!启动它,然后通过向数据库添加行来向其发送命令。尝试以下各项:

$ echo pie >> /tmp/db.dat  # start new thread

$ echo pie_stop >> /tmp/db.dat # stop thread by event

$ echo whiskey_stop >> /tmp/db.dat # stop another thread "

$ echo stop >> /tmp/db.dat # stop all threads

import logging, sys, threading, time

STOP_VALUE = 'stop'

logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)-4s %(threadName)s %(levelname)s %(message)s", 
    datefmt="%H:%M:%S",
    stream=sys.stderr,
)


class Database(list):
    PATH = '/tmp/db.dat'
    def __init__(self):
        super(Database,self).__init__()
        self._update_lock = threading.Lock()

    def update(self):
        with self._update_lock:
            self[:] = [ line.strip() for line in open(self.PATH) ]

db = Database()

def spawn(events, key):
    events[key] = threading.Event()
    th = threading.Thread(
        target=search_worker,
        kwargs=dict(stop_ev=events[key]),
        name='thread-{}'.format(key),
    )
    th.daemon = True
    th.start()

def search_worker(stop_ev):
    """
    scan database until "stop" found, or our event is set
    """
    logging.info('start')
    while True:
        logging.debug('scan')
        db.update()
        if STOP_VALUE in db:
            logging.info('stopvalue: done')
            return
        if stop_ev.wait(timeout=10):
            logging.info('event: done')
            return 

def manager():
    """
    scan database
    - word: spawn thread if none already
    - word_stop: tell thread to die by setting its stop event
    """
    logging.info('start')
    events = dict()
    while True:
        db.update()
        for key in db:
            if key == STOP_VALUE:
                continue
            if key in events:
                continue
            if key.endswith('_stop'):
                key = key.split('_')[0]
                if key not in events:
                    logging.error('stop: missing key=%s!', key)
                else:
                    # signal thread to stop
                    logging.info('stop: key=%s', key)
                    events[key].set()
                    del events[key]
            else:
                spawn(events, key)
                logging.info('spawn: key=%s', key)
        time.sleep(2)


if __name__=='__main__':

    with open(Database.PATH, 'w') as dbf:
        dbf.write(
        'whiskey\nsyrup\n'
        )

    db.update()
    logging.info('start: db=%s -- %s', db.PATH, db)

    manager_t = threading.Thread(
        target=manager,
        name='manager',
    )
    manager_t.start()
    manager_t.join()

答案 1 :(得分:0)

相反,改变你的设计架构并进行分布式进程到进程的消息传递,而不是在无限循环中重复地追逐dbEngine,重复的dbSeek-s用于哑值,重新测试它一个不平等,然后试图杀死一个睡眠"。

在这种意义上, ZeroMQ nanomsg 都是智能的,无代理的,消息传递层非常好。

渴望交火和水恕我直言,并没有为现实世界的系统带来任何好处。

智能,可扩展,分布式的流程到流程设计。

( Fig. on a simple distributed process-to-process messaging, courtesy imatix/ZeroMQ )

(关于简单的分布式流程到流程的消息/协调,图片由imatix / ZeroMQ提供)