Python 中 Windows 中的全局变量范围

Scope of Global variables in Python in Windows

我有一个 CLI 脚本,我用它来将文件推送到 s3 存储桶中。 对于较大的文件,我将文件分成几部分并上传 在平行下。 (在这里粘贴代码结构。我试着做一个极简主义的例子,但即使是 60 行长)

def _upload_part(argFile, argBucket, max_attempts_limit, **core_chunk):
    #bunch of stuff
    pool = Pool(processes=parallel_processes)
    for i in range( chunk_amount ):
        #bunch of stuff
        pool.apply_async( _upload_for_multipart, [keyname, offset, mp, part_num, bytes] )
    pool.close()
    pool.join()

def _upload_for_multipart(keyname, offset, mp, part_num, bytes):
    #code to upload each part
    #log the status of each part to log files

def _get_logger( pdir, ldir, lname, level, fmt ):
    os.makedirs( logs_dir )
    logging.basicConfig(
        filename=os.path.join(logs_dir, lname),
        level=level,
        format=fmt
    )
    return logging.getLogger( lname )

#under main
if __name__ == "__main__":
    logneeds = dict( pdir=exec_dir, ldir='logs', lname='s3_cli.log', level='INFO',
                               fmt='%(asctime)s %(levelname)s: %(message)s' )
    logger = _get_logger(**logneeds)

以上代码结构在 OSX 和 Linux 中有效,但在 windows 中失败。它说 name 'logger' is not defined下的_upload_for_multipart函数。全局变量的方式有区别吗 在 windows 和基于 unix 的 OS?

中解释

编辑:添加了工作示例 here

您看到的是 child 进程在 Windows 与 UNIX-y OSes(或任何 OS 支持 fork)。在 Linux 上,fork 用于创建 child 进程,它在 parent 进程的 copy-on-write 副本中创建 child。这意味着 parent 中存在的所有变量都将出现在 child.

Windows,但是不支持fork。为了创建 child,它产生一个 brand-new 进程,然后 re-imports child 中 parent 的 __main__ 模块。在您的情况下,这意味着脚本 运行 您的程序被导入 child。 logger 的创建发生在 parent 中的 if __name__ == "__main__": 守卫内部,这意味着当 child 导入模块时它会被跳过。 multiprocessing 文档中有几个地方提到了这一点,我在 .

中明确列出了这一点

为了让 logger 存在于 children 中,它需要在模块的 top-level 中创建(这意味着它会在您每次导入时运行它),或者您需要在所有 child 进程中显式创建它,也许使用 multiprocessing.Pool:

initializer 参数
logger = None

def init_log():
    global logger
    logneeds = dict(pdir=exec_dir, ldir='logs', lname='s3_cli.log', level='INFO',
                    fmt='%(asctime)s %(levelname)s: %(message)s' )
    logger = _get_logger(**logneeds)

def _upload_part(argFile, argBucket, max_attempts_limit, **core_chunk):
    #bunch of stuff
    pool = Pool(processes=parallel_processes, initializer=init_log)
    for i in range( chunk_amount ):
        #bunch of stuff
        pool.apply_async( _upload_for_multipart, [keyname, offset, mp, part_num, bytes] )
    pool.close()
    pool.join()

def _upload_for_multipart(keyname, offset, mp, part_num, bytes):
    #code to upload each part
    #log the status of each part to log files

def _get_logger( pdir, ldir, lname, level, fmt ):
    os.makedirs( logs_dir )
    logging.basicConfig(
        filename=os.path.join(logs_dir, lname),
        level=level,
        format=fmt
    )
    return logging.getLogger( lname )

#under main
if __name__ == "__main__":
    init_log()