zoukankan      html  css  js  c++  java
  • Python 的 import 缓存机制与 s3fs 的冲突

    背景

    一个用来运行 Python 代码的 Jupyter 服务,由于某些原因,将 Python 的 pip 包安装目录使用 s3fs 挂载到了 MinIO。
    然后就发生了一个很奇怪的现象,当使用
    ! pip install module
    安装某个包,然后代码中使用
    import module
    来导入包时,总会报错显示找不到包。但当重启了 jupyter 服务后,import module 就会正常运行。
     

    排查步骤及原因分析

    一、确认在 !pip install module 执行之后,在 import 执行前,对应库的安装文件确实存在。
     
    通过如下代码确认包安装后的路径:
    import module
    print(module)
    结果是文件确实存在。
     
    二、研究 Python 的导包机制,分析为何没有找到包。
     
    具体源码参见 importlib 标准库。通过追踪如下代码的调用链
    importlib.import_module("module")
    发现有几个可疑点使用了缓存:
     
    1. sys.path_importer_cache
     
      此对象数据结构就是一个字典。key 是路径,value 是查找器对象(比如 importlib._bootstrap_external.FileFinder )
    每次对包的查找,都会使用这个缓存来记录查找过的路径。这样下次就可以很快的定位,主要是为了提高找包效率。
    当导入一个包时,包所在的目录及其上级目录都会在 sys.path_importer_cache 里有记录。这样当第二次导入同目录下的包时,就不需要再次遍历子目录。
    但同样的,如果缓存的 value 出了问题,那么就会影响此路径下包的导入
     
    2. importlib._bootstrap_external.FileFinder
     
      此对象在构建时会缓存指定路径下的目录列表。避免多次调用操作系统接口来获取目录,也是为了提高效率。
    但目录下的文件在安装包之后是会变化的,所以 FileFinder 本身也有一个机制来发现目录的变化,用的是目录的 mtime 修改时间
    mtime = _path_stat(self.path or _os.getcwd()).st_mtime
    // posix.stat(path).st_mtime
    // nt.stat(path).st_mtime
    当发现目录的 mtime 发生了变化时,会刷新缓存。
    看起来很合理,也确实合理,但就是还是找不到包。
     
    三、重点锁定 FileFinder 的缓存机制,测试是否触发了缓存刷新。
     
    通过输出 !pip install module 执行前后,对应目录的 mtime, 发现没有变化而且都是 0。
    此时问题其实就定位到了 s3fs 挂载的目录无法修改 mtime 的问题。
     
    正常的操作系统目录,当目录内有文件发生改变时,目录的 mtime 也会相应发生改变。而通过 s3fs 挂载的目录则不会。
    也没有办法修改。
     
    猜测一下原因:
      S3本来是没有目录的概念的,所谓的目录仅仅是对同样前缀的文件的虚拟,并不是真实存在的一个东西。
    但一般文件系统的目录是真实存在于磁盘上。所以如果要实现目录内文件修改的同时同步修改目录属性,则
    s3fs 就需要额外的地方来存储这些信息,但这些信息无论是放在主机上,还是放在S3上都不太合适。一旦支
    持了,就需要考虑多主机挂载同一目录时的同步问题。
     

    解决方案

    s3fs 这个mtime为0的问题无法解决,所以目录一旦缓存就无法自动刷新。
    所能做的就是在每次 !pip install module 之后手动将 sys.path_importer_cache 置为空字典,强制触发磁盘扫描。
     
    参考文档:

     
     
     
     
     
     
  • 相关阅读:
    大白话五种IO模型
    test
    shutil模块(了解)
    isinstance和issubclass
    变量的三个特征
    匿名函数
    javascript location 对象
    select元素javascript常用操作
    设置mysql的用户权限
    jquery
  • 原文地址:https://www.cnblogs.com/dyfblog/p/15767748.html
Copyright © 2011-2022 走看看