CPython的os.listdir
实现使用平台特定的C库调用来读取目录内容。在类Unix平台上,这些调用是opendir(3)
和readdir(3)
,在Windows上则使用FindFirstFile
和FindNextFile
。
这些调用在网络文件系统不可达时的行为将取决于操作系统。当使用Linux或Windows时,在那些系统命令(如
ls
)挂起的情况下,它们肯定会挂起。为了防止任意长时间的暂停,可以使用专门的框架,例如
asyncio和
twisted,它们利用非阻塞IO。使用这些框架可能很困难,并且通常需要在整个应用程序和整个程序中使用它们来实现事件驱动模型。
确保IO系统调用在存在网络文件系统的情况下不会被阻塞的一种更简单、适合初学者的方法是使用线程。以下是一个例子
safe_listdir
函数,返回目录内容,或者如果调用超过指定的超时时间,则返回
None
:
import os, threading
def safe_listdir(directory, timeout):
contents = []
t = threading.Thread(target=lambda: contents.extend(os.listdir(directory)))
t.daemon = True
t.start()
t.join(timeout)
if t.is_alive():
return None
return contents
在Python 3中,可以使用优秀的"concurrent.futures"包。它不仅简化了实现过程,还会自动限制创建的线程数量,如果"safe_listdir"被多次调用,并确保在"os.listdir"中引发的异常正确地传播到调用者:
import os, concurrent.futures
pool = concurrent.futures.ThreadPoolExecutor()
def safe_listdir(directory, timeout):
future = pool.submit(os.listdir, directory)
try:
return future.result(timeout)
except concurrent.futures.TimeoutError:
return None