能否使用os.listdir列出网络驱动器中的文件?它使用哪个系统调用?

4
os.listdir内部执行哪个系统调用,Python进程是否会因os.listdir在挂载的网络驱动器上运行而挂起?
我们怀疑我们的应用服务器出现了问题,因为os.listdir试图列出挂载在Linux机器上的Samba共享。显然,Samba共享的DNS在我们遇到这个问题的前后发生了变化。我们仍在尝试复制这种情况,但有人能告诉我它是如何工作的吗?并且像ls这样的命令也会像这样挂起吗?
有没有办法在用户空间处理这个问题?
1个回答

6

CPython的os.listdir实现使用平台特定的C库调用来读取目录内容。在类Unix平台上,这些调用是opendir(3)readdir(3),在Windows上则使用FindFirstFileFindNextFile

这些调用在网络文件系统不可达时的行为将取决于操作系统。当使用Linux或Windows时,在那些系统命令(如ls)挂起的情况下,它们肯定会挂起。为了防止任意长时间的暂停,可以使用专门的框架,例如asynciotwisted,它们利用非阻塞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  # don't delay program's exit
    t.start()
    t.join(timeout)
    if t.is_alive():
        return None  # timeout
    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  # timeout

有没有办法可以在不修改内核实现的情况下处理这些事情?例如设置超时,这样做不是很有意义吗? - Nishant
很棒,我没怎么使用过线程。但这是学习这些概念的好例子。我会看一下这个例子。它类似于将“网络连接检查”与真正的Python分离或类似的东西。 - Nishant
1
@Nishant编辑了答案,删除了“死亡”管理。事实证明,Python线程不需要成功“加入”即可在自身清理后完成。 - user4815162342

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接