文章来源于互联网(https://jq.qq.com/?_wv=1027&k=rX9CWKg4)

在Python中,被称为「程序的入口」的 if name ==‘main’: 总是出现在各种示例代码中,有一种流传广泛的错误观点是「这只是Python的一种编码习惯」。事实上程序的入口非常有用,绝非可有可无,例如在Python自带的多线程库要求必须把主进程写在 if入口内部才能正常运行。

直接写在Python最左端没有缩进的代码,在这个 *.py 文件被直接运行、或者被调用时会被执行,只有写在 if name ==‘main’: if入口内部才不会在被调用时执行。Python用这个简单的方法来判断当前的模块是被直接运行还是被调用,这是很重要的功能,如:

  • 我们可以把不想在被调用时执行的代码放在程序入口的if内部,比如自检程序。
  • 我们还把多线程的主线程写在程序入口的if内部。只能这么做,避免自己调用自己时重复执行主进程,下面会详细解释。

因此,初学Python时,直接把主程序写在不需要缩进的位置,完全不写 if name ==‘main’: 当然可以。一个既没有写一个被调用的库的能力,也不一定要学多进程的新手,很容易错误地认为「程序的入口」没什么用。

类似的,还有被少数人误解的还有 Python的文件头:

#!/bin/bash/python3  # 这一句话用来在代码被执行时,主动说明该选哪个路径下的编译器
#!/bin/bash/python2 # 例如这一句就选了Python2,不过2020年Python2快要完成过渡使命了

2020年底,我在写Python多进程教程时,没有搜索到合适的文章解释“程序的入口 if name ==‘main’: 与多线程的必要联系”,反而看到了很多高赞的片面回答。无奈之下只能自己写。对于少数有基础的人,下面讲程序入口与多线程部分也值得一看。

目录

  • 「程序的入口」是什么?
  • 程序入口与自检程序
  • 程序入口与多线程

更新日志

  • 第一版 2021-01-01 我会把评论区的好问题更新到正文里

「程序的入口」是什么?

用很短的话就能解释,我认可菜鸟分析↓的回答 ,部分高赞答案写得啰嗦

name 是当前模块名,当模块被直接运行时模块名为 main 。这句话的意思就是,当模块被直接运行时,以下代码块将被运行,当模块是被导入时,代码块不被运行。

举例说明:当我在终端直接运行 python3 run1.py时,模块名被一律改为字符串__main__,当模块是被另一个 *.py程序导入(如在 *.py 中 import run1)而不是直接运行时,模块名是字符串run1。

在C语言和Java里也有类似的「程序入口」:


# Python的程序入口
if __name__ =='__main__': # 它对多进程非常重要
# 这里是主程序 # C语言的程序入口
void main(){
/* 这里是主程序 */
} # Java的程序入口
public static void main(String[] args){
// 这里是主程序
}

检验一下自己:下面的程序会print出什么东西?

# 新建一个名为【run1.py】的文件,填入下方代码
# 然后在终端输入【python3 run1.py】并运行 print(__name__, 'run1-outside') # 它会print出【__main__ run1-outside】
if __name__ =='__main__':
print(__name__, 'run1-inside') # 它会print出【__main__ run1-inside】

再检验一下自己:


# 新建另一个名为【run2.py】的文件,填入下方代码,并放在与【run1.py】的相同目录下,
# 然后在终端输入【python3 run2.py】并运行。用run2 调用run1 import run1 # 这一行代码调用了外部的代码 run1,它只会print出:
# 【run1 run1-outside】 # 它只print出这一行东西,并且run1.py的【__main__】变成了【run1】
# 【run1 run1-inside】 # 写在run1【if】缩进里的东西都没有被执行 print(__name__, 'run2-outside') # 它会print出【__main__ run2-outside】
if __name__ =='__main__':
print(__name__, 'run2-inside') # 它会print出【__main__ run2-inside】

程序入口与自检程序

当一个开发者编写一个库时(例如把它命名为 utils.py),如


# 这个库(模块)被命名为 utils.py
class C1:
...
def func1():
... c1 = C1() # 这是错误的做法,应该挪到 程序入口if内部
func1() # 这是错误的做法,应该挪到 程序入口if内部
if __name__ =='__main__':
c = C1()
func1()

当其他人只想调用 C1 或者 func1时,他在另一个Python文件中,用 import utils 导入 utils这个库时就不会运行程序入口if内部的任何代码了。

程序入口与多线程

实现多线程时,「程序入口」这个功能不可或缺。我需要同时运行多个 fun1,或者同时运行 fun1 fun2 … 如下:


def function1(id): # 这里是子进程
print(f'id {id}') def run__process(): # 这里是主进程
from multiprocessing import Process
process = [mp.Process(target=function1, args=(1,)),
mp.Process(target=function1, args=(2,)), ]
[p.start() for p in process] # 开启了两个进程
[p.join() for p in process] # 等待两个进程依次结束 # run__mp() # 主线程不建议写在 if外部。由于这里的例子很简单,你强行这么做可能不会报错
if __name__ =='__main__':
run__mp() # 正确做法:主线程只能写在 if内部

当我运行上面这个程序,它的【name ==‘main’】,因此它会执行 【if】内的代码。这些代码会创建新的多个子进程,自己调用自己。在被调用的子进程中,它的【name】 不等于【main】,因此它只会执行被主进程分配的任务(比如fun1),而不会像主进程一样通过「程序入口」再调用别的进程(行此僭越之事)。这是一个非常重要的功能,这里讲的不仅是Python,其他成熟的编程语言也能用相似的方法。

尽管有很多人点踩,但是这个分析是正确的。点踩的可能是其他原因引发了错误

尽管forkserver 依然不如 spawn更节省资源,但能解决问题也算不错了

由于我上面的例子过于简单(没有涉及进程通信、进程退出条件),如果你强行把主进程写在 if外部,也可能不会看到报错。这涉及很多因素,它与你使用的系统、子进程的创建方式(spwan、fork、forkserver、force=True/False)有关。我在这里只讲「程序的入口」,更多内容请移步
“ Compulsory usage of if name==“main” in windows while using multiprocessing - Stack Overflow ”
Tim Peters 与 David Heffernan 的回答都不错。

尽管Python的多进程已经做得挺不错了,希望随着以后版本的更新,多进程与「程序入口」的依赖关系应该能得到更好的解决。

使用PyTorch CUDA multiprocessing 的时候出现的错误 UserWarning: semaphore_tracker

(写于2021-03-03)

错误如下:


multiprocessing/semaphore_tracker.py:144:
UserWarning: semaphore_tracker: There appear to be 1 leaked semaphores to clean up at shutdown
len(cache)) Issue with multiprocessing semaphore tracking

相同问题描述:

解决方案:

即在运行 .py 文件前,使用以下语句修改环境参数,忽略这个Warning 带来的程序暂停

export PYTHONWARNINGS='ignore:semaphore_tracker:UserWarning'

等同于在 .py 文件内部使用:

os.environ['PYTHONWARNINGS'] = 'ignore:semaphore_tra

Python程序入口 __name__ == ‘__main__‘ 有重要功能(多线程)而非编程习惯的更多相关文章

  1. Python:if __name__ == '__main__'

    简介: __name__是当前模块名,当模块被直接运行时模块名为_main_,也就是当前的模块,当模块被导入时,模块名就不是__main__,即代码将不会执行. 关于代码if __name__ == ...

  2. python中if __name__ == '__main__'

    python 中__name__ = '__main__' 的作用,到底干嘛的? 有句话经典的概括了这段代码的意义: “Make a script both importable and execut ...

  3. python中if __name__ == '__main__': 解析

    当你打开一个.py文件时,经常会在代码的最下面看到if __name__ ==  '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一 ...

  4. python 中if __name__ = '__main__' 的作用

    python 中if __name__ = '__main__' 的作用 前言 首先我们要知道在python里面万物皆对象,模块也是对象,并且所有的模块都有一个内置属性 __name__. 一个模块的 ...

  5. python中if __name__ == '__main__': 的解析

    当你打开一个.py文件时,经常会在代码的最下面看到if __name__ ==  '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一 ...

  6. python基础之python中if __name__ == '__main__': 的解析

    当你打开一个.py文件时,经常会在代码的最下面看到if __name__ == '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一个 ...

  7. 【python】if __name__ == '__main__'

    转载自:http://www.cnblogs.com/xuxm2007/archive/2010/08/04/1792463.html 当你打开一个.py文件时,经常会在代码的最下面看到if __na ...

  8. Python常见经典 python中if __name__ == '__main__': 的解析

    当你打开一个.py文件时,经常会在代码的最下面看到if __name__ == '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一个 ...

  9. python中if __name__ == '__main__': 的解析(转载)

    当你打开一个.py文件时,经常会在代码的最下面看到if __name__ == '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一个 ...

随机推荐

  1. 关于 display: inline-block; 中间有间隙的问题

    当我们给一个元素的一系列子元素设置display: inline-block; 时,会发现子元素之间存在间隙,如 <style> div { display: inline-block; ...

  2. Intellij IDEA 高效使用教程 (插件,实用技巧) 最好用的idea插件大全

    安装好Intellij idea之后,进行如下的初始化操作,工作效率提升十倍. 一. 安装插件 1. Codota 代码智能提示插件 只要打出首字母就能联想出一整条语句,这也太智能了,还显示了每条语句 ...

  3. 从0开始基于Webpack5 搭建HTML+Less 前端工程

              基于Webpack5 搭建HTMl+Less的前端项目 新建一个文件夹(比如命名为webpack) 用编辑器打开该文件夹,并在编辑器的终端执行 npm init -y 自动创建pa ...

  4. VMWARE vcenter重置root密码

    1\重启VCSA 2\在GNU GRUBc的时候,按住e键,在后面加上一句命令 3.rw init=/bin/bash 4. 按CTRL-X或者按住F10,启动系统 5. 使用passwd命令修改ro ...

  5. Visual Studio之安装(更新,扩展)速度缓慢解决方案

    一.背景 小伙伴们在安装visual studio,或者更新,扩展vs功能时,在家里网速正常的情况下,可能出现进度十分缓慢的问题,如何解决呢? 二.解决思路 修改hosts文件 1.地址:默认安装在 ...

  6. Jenkins安装详解

    一.Jenkins是什么 Jenkins是一个独立的开源自动化服务器,可用于自动执行与构建,测试,交付或者部署软件相关的各种任务,是跨平台持续集成和持续交付应用程序,提高工作效率.使用Jenkins不 ...

  7. 923. 3Sum With Multiplicity - LeetCode

    Question 923. 3Sum With Multiplicity Solution 题目大意: 给一个int数组A和一个目标值target,求满足下面两个条件的组合个数,其中i,j,k分别为数 ...

  8. 590. N-ary Tree Postorder Traversal - LeetCode

    Question 590. N-ary Tree Postorder Traversal Solution 题目大意:后序遍历一个树 思路: 1)递归 2)迭代 Java实现(递归): public ...

  9. Property or method "xxx" is not defined on the instance but referenced during render

    是xxx中的data写成date了,因此报错. 这个错误属于粗心

  10. 使用多线程提高REST服务器性能

    异步处理REST服务 1.使用Runnable异步处理Rest服务 释放主线程,启用副线程进行处理,副线程处理完成后直接返回请求 主要代码 import java.util.concurrent.Ca ...