3

所以我是python的初学者,正在研究文件系统事件处理程序。我遇到了看门狗 api,在那里我看到了一个我无法理解的多线程代码。

这是他们网站上发布的代码:

import sys
import time
import logging
from watchdog.observers import Observer
from watchdog.events import LoggingEventHandler

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s - %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')
    path = sys.argv[1] if len(sys.argv) > 1 else '.'
    event_handler = LoggingEventHandler()
    observer = Observer()
    observer.schedule(event_handler, path, recursive=True)
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

此代码运行无限循环并侦听某个文件夹并将看到的内容记录到控制台。我的疑问是在代码的底部。

所以你启动观察者。然后要求它进行无限循环,直到完成某个按键操作。我假设在“observer.start()”代码的某个地方,他们也设置了 daemon=True。在某些按键下,程序会跳出循环并停止观察者。在看门狗的 api 中,stop() 的定义说它停止了守护线程。

1) 然后它执行一个join()。但是这个加入有什么需要。我已经停止了守护线程。不是 join() 意味着等待所有线程停止然后才退出程序。我可以从代码中删除 join() 吗?删除它后,我的程序仍然可以正常工作。

2)我也不明白 while 循环内需要 sleep(1) 。如果我只是在那里放一个“通过”声明会发生什么。我假设while循环会消耗更多资源???以及我们将睡眠时间设置为 1 秒而不是 2-3 秒的原因,因为在最坏的情况下,用户可能需要等待 2-3 秒才能关闭程序。但我可能错了。

4

1 回答 1

1
  1. 请记住,守护进程正在父进程的进程中运行。您需要在该线程执行时保持父进程处于活动状态,否则它将在程序退出时被杀死(并且可能以一种不优雅的方式)。这样join可以确保进程保持活动状态,直到所有线程实际退出;仅仅因为您调用stop并不能保证线程实际上已完成执行。stop是线程停止的请求,它不需要阻塞,直到线程终止(也不应该这样父线程可以stop“一次”调用许多子线程)。

  2. 这纯粹是为了减少 CPU 消耗。如果你只是pass
    那里有一个,CPU会尽可能快地运行那个while循环,从而减少循环。该sleep调用自愿将 CPU 让给其他进程,因为它知道不需要快速响应任何特定条件。而且您基本上是正确的,sleep(1)因此您的最坏情况响应时间约为 1 秒。

更新:

这是一个为什么拥有 ajoin很重要的例子。假设以下内容在线程中运行:

while not self.stop:  # self.stop is set to True when stop() is called
    ...
    self.results.append(item) # do some stuff that involves appending results to a list
with open('~/output.txt', 'w') as outfile:
    outfile.write('\n'.join(str(item) for item in item))

stop被调用时,while 循环将终止,结果文件将打开并开始写入。如果join未调用 ,则进程可能会在write操作完成之前终止,这将导致结果损坏。join确保父线程等待此写入完成。它还确保该过程实际上等待该while循环的整个迭代完成;如果没有,join您不仅会错过文件写入,还会在该while块的中间终止。

但是,如果调用它的线程 在终止stop后没有做任何事情,则会立即有效地返回,因此基本上变成了 NOP。whilejoin

更新 2:

关于睡眠调用,某些事件(例如)甚至可以从父进程ctrl+c的调用中冒出来。sleep所以在这种特殊情况下,睡眠时间的长短并没有那么重要。将其设置为 1 秒主要是为了清楚表明您基本上是在做一个“让 CPU”而不是真正睡觉睡觉。

于 2014-10-13T14:24:06.837 回答