Python之进程+线程+协程(multiprocessing多进程模块)

前几篇的多线程模块的各种规则和用法,本篇则是关于多进程模块的内容
1、multiprocessing的介绍
在Python中,由于有GIL解释器锁的存在,多线程就根本不是本质意义上的多线程,而是一个主线程我们通过控制子线程来实现的,本质上还是只有一个线程,没有并行效果。

但我们想要充分地使用多核CPU的资源,在Python中大部分情况都需要使用多进程。

multiprocessing包是Python中的多进程管理包。
与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。
该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。
此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。
所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情境。

2、多进程的直接调用
(1)测试代码:

from multiprocessing import Process  #导入多进程模块
import time

def foo(name):
    time.sleep(1)
    print('Hello,', name,time.ctime())

if __name__ == '__main__':
    p_list=[]
    for i in range(3):
        #创建多进程对象,传入函数名和函数需要的参数
        p = Process(target=foo, args=('Zahi',))

        #启动多进程
        p_list.append(p)
        p.start()
        
    for i in p_list:
        p.join()
        
    print('---------------------end----------------------')

(2)测试结果:
1
可以看到,函数内是输出语句根本没有输出到屏幕上,但是也没有任何报错语句,这是为什么呢?

本人反复检查代码也没有找出任何逻辑错误,后来通过查阅资料了解到,这是IDLE多进程的一个坑。

(3)print内容不显示的原因:
spyder使用的stdout和windows不支持forking,所以无法打印子进程内容。

The comments revealed that OP uses Windows as well as Spyder. Since Spyder redirects stdoutand Windows does not support forking, a new child process won’t print into the Spyder console. This is simply due to the fact that stdout of the new child process is Python’s vanilla stdout, which can also be found in sys.stdout.

(4)两种解决方法:
1.打印日志到文件。2.用返回值替代打印。

import multiprocessing
 
def worker(num):
    """Returns the string of interest"""
    return "worker %d" % num
 
def main():
    pool = multiprocessing.Pool(4)
    results = pool.map(worker, range(10))
 
    pool.close()
    pool.join()
 
    for result in results:
        # prints the result string in the main process
        print(result)
 
if __name__ == '__main__':
    # Better protect your main function when you use multiprocessing
    main()

参考文章:【Python有坑系列】python多进程,函数内print的内容没有打印出来

(5)改进后的代码:

import multiprocessing  #多进程模块
import time

def foo(n):
    time.sleep(1)
    return n,'-Hello,Zohi!',time.ctime()
    

if __name__ == '__main__':
    Li= []
    #实例化多进程对象
    p= multiprocessing.Pool(4)
    results= p.map(foo,range(5))
    
    p.close()  #关闭多进程
    p.join()

    for result in results:   
        print(result)
    


    print('---------------------end-------------------------')

(6)改进结果:
2
可以看到,五个进程同时运行,时间都精确到秒数了

3、继承式调用


from multiprocessing import Process
import time

#继承式调用多进程
class MyProcess(Process):
    def __init__(self,name):
        super(MyProcess, self).__init__()
        self.name = name

    def run(self):
        time.sleep(1)
        print('hello', self.name,time.ctime())


if __name__ == '__main__':
    p_list=[]
    for i in range(3):
        p = MyProcess('Zahi')
        p.start()
        
        p_list.append(p)

    for p in p_list:
        p.join()

    print('--------------------end---------------------')

4、Process下的方法
(1)构造方法:

Process([group [, target [, name [, args [, kwargs]]]]])
  group: 线程组,目前还没有实现,库引用中提示必须是None;
  target: 要执行的方法;
  name: 进程名;
  args/kwargs: 要传入方法的参数。

(2)实例方法:

is_alive():返回进程是否在运行。
 join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。
 start():进程准备就绪,等待CPU调度
 run():strat()调用run方法,如果实例进程时未制定传入target,这star执行t默认run()方法。
 terminate():不管任务是否完成,立即停止工作进程

(3)属性:

daemon:和线程的setDeamon功能一样
 name:进程名字。
 pid:进程号。

(4)练习代码:

import time
from  multiprocessing import Process

def foo(i):
    time.sleep(1)
    return p.is_alive(),i,p.pid
    time.sleep(1)

if __name__ == '__main__':
    p_list=[]
    for i in range(10):
        p = Process(target=foo, args=(i,))
        #p.daemon=True  #相当于线程方法里的setDaemon
        print(p)
        p_list.append(p)

    for p in p_list:
        p.start()
        
    for p in p_list:
        p.join()

    print('--------------------end----------------------')

3

猜你喜欢

转载自blog.csdn.net/Viewinfinitely/article/details/105513038