python3中的多任务编程
python中子线程如何向父线程回传参数呢?
答:最基础的方法是在单文件的开头定义一个全局变量,再加一个锁,就可以父进程、子进程共享一个变量了。
在一个单核CPU上,要同时跑多个任务,比如在写文档的同时听歌,就可以使用多进程的技术。每个任务就是一个进程(Pocess)。多进程就是交替的使用CPU的一段运行时间,当交替的很快,多个进程看起来就跟在同时执行一样。在一个任务背后,又可能需要同时执行多个子任务,这时每个子任务被称为线程(Thread)。线程的并发也是交替使用CPU。
当我们要同时执行多个任务,可以启用多个进程或线程。多个任务之间往往是需要通信和协调的,这也是同时执行多任务的难点所在。
就我自己执行的任务来说,我在一个mininet(仿真软件)的进程中开启多个线程,以实现多任务。所谓的多任务,是要模拟多台主机同时产生流量的一个过程。每台主机按照一定规律产生流量,在同一时间,这些流量的汇聚结果也就是我需要观察的内容。
在这个过程中,容易的点在于这多个主机相互独立的产生流量,并不存在一个主机要等在另一个主机后产生流量,或者说这个主机产生的流量大小要和另一个主机的流量大小成正比。在其中有一个小小的约束条件,就是等待所有的主机停止产生流量后,才能进行相关的统计。因此在使用过程中用了线程锁,每当一个主机停止产生流量,就解锁一个对应的线程锁。所有线程锁解锁后,才能进行统计。
问:在这个过程中,不禁产生问题,在开启多线程后,有一个while循环不停在统计线程锁是否解锁完。此时的while循环运行在线程还是进程上呢?
答案:while 是运行在线程上的。进程开启时会默认有一个主线程;新生成的线程就是新生成的线程
问:Linux系统中,输入ps -ef会打印出某个程序的PID, PPID,是什么意义呢?
答:PID是指这个进程的ID,PPID是指这个进程的父进程的PID
问:在一个线程中生成多个子线程,每个线程又分别利用mininet中定义的host.cmd()命令调用函数产生流量,这时每个host上运行的是进程还是线程呢?
答:首先,生成的子线程共用一个进程,且每个线程各自有独立的线程ID。如下图
注意,此时这些子线程只是拥有拓扑中各个节点的接口,并未实际使用各个节点。此时所有子线程仍然运行在mininet命令行函数对应的那个进程,即进程5947
接着这些子线程各自调用拓扑中的节点,并在节点中运行相应的子程序。这些子程序会打印自己所在的进程与父进程,如下图。可以看到,每个子程序运行在不同进程中,并且每个子程序的父进程都不一样。
由此可以总结,在mininet上用多主机同时产生流量的时候,每个主机的打流都是运行在不同进程上的。可为何调用大量主机产生流量时,哪怕仿真的系统已经不堪重负,CPU利用率仍然不高呢?推测可能是由于线程之间通信需要等待(以便将各个主机的流量汇集在一起),让CPU利用率不是特别高的情况下,各个主机间信息的协调就已经出让仿真系统不堪重负。
问:python对象是如何在函数中传递的。多层传递有什么弊端吗
答:在函数中传递时,如果是不可变类型的对象,如整数、元组、字符串,那么这些对象会在内存中复制一遍,传到函数中;如果是列表、字典等不可变对象,传递的是这些对象在内存中的地址,在函数中修改可变对象,外部也会被修改。
python多进程
在Unix/Linux下,可以使用fork()
调用实现多进程。
要实现跨平台的多进程,可以使用multiprocessing
模块。
进程间通信是通过Queue
、Pipes
等实现的。
python多线程
运行一个python脚本,就会打开一个进程,进程默认有一个主线程跑代码。
多个线程之间共享变量,可以使用lock类来确保变量之间的同步。lock.acquire(), lock.release()
python编译器自带一个GIL(Global Interpreter Lock)锁,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。
要利用多核CPU的性能,在python中可以使用多进程的方法。尝试如下
采用四核八线程CPU,则每个编译器中的进程最多可利用17.5%的计算能力。
开两个进程,可以让CPU的利用率升到32%。开心
threading.local() (注:新建为全局变量) 可以解决线程内函数传递对象参数问题。像一个字典一样,利用不同线程不同的ID来调用属性,因此属性也就各自对应到了线程中。
多进程 VS 多线程
多进程模式稳定性高,一个子进程挂掉,主进程和其他子进程都能正常工作。但创建进程代价大,执行效率低。
多线程模式通常比多进程快。但多线程不稳定,任何一个线程挂掉都可以造成整个进程崩溃,因为所有线程共享进程的内存。
计算密集型任务需要进行大量计算,为保证高效,任务数应相对于CPU的核心数,且用C语言编写比较合适
IO密集型任务设计到网络、磁盘IO任务,特点是CPU消耗少,大部分时间在等待IO操作完成。IO密集型任务常用脚本语言编写,因为其开发效率高,且基本不影响IO密集型任务的效率
当执行多任务时,涉及到保存现场、准备新环境等操作。当几千个任务同时进程,操作系统可能主要做的事就是忙着切换任务,真正做任务的时间很少。这种情况最常见的就是硬盘狂响,点窗口无反应,系统处于假死状态。