Python 线程和进程(2)

IO操作不占用cpu
计算占用cpu
 
python多线程 不适合cpu密集操作类型的任务 适合IO操作密集型任务 
 
简单一个进程实例:
import multiprocessing #进程模块
import time

def run(name,proce):
    time.sleep(1)
    print("hello",name,proce)

if __name__ == '__main__':

    for i in range(10):
        p = multiprocessing.Process(target=run,args=('liyang',i,))
        p.start()
    p.join()

进程里面能起线程吗?当然可以:

# -*- coding:utf-8 -*-
# Author:Brownyangyang
import multiprocessing
import time
import threading

def threadtest():
    print(threading.get_ident())  ##获取线程号

def run(name,proce):
    time.sleep(2)
    print("hello",name,proce)
    t = threading.Thread(target=threadtest,)
    t.start()

if __name__ == '__main__':

    for i in range(5):
        p = multiprocessing.Process(target=run,args=('liyang',i,))
        p.start()
    p.join()

关于进程号

import multiprocessing
import os

def info(title):
    print(title)
    print("module name:",__name__)
    print("parent process:",os.getppid()) ##打印父进程
    print("process id:",os.getpid())  ##打印当前进程
    print("------------------------")
def f(name):
    info("33[031;1mfunction f33[0m")
    print("hello",name)

if __name__ == "__main__":
    info("33[032;1mmain process line33[0m")
    p = multiprocessing.Process(target=f,args=("liyang",))
    p.start()
    p.join()

结果( 这个310进程是pycharm的进程):

main process line
module name: __main__
parent process: 310
process id: 47385
------------------------
function f
module name: __main__
parent process: 47385
process id: 47386
------------------------
hello liyang
 
 
进程间是无法通信,如果非要通信,有以下几种办法:
 
一、使用进程Queue(这里不同于线程的queue)
# -*- coding:utf-8 -*-
# Author:Brownyangyang
from multiprocessing import Process,Queue
#这里导入的是multiprocessing的Queue模块,不是小写哦,小写queue是线程queue

def f(qq):
    qq.put([42,None,'hello'])

if __name__ == '__main__':
    q = Queue()
    p = Process(target=f,args=(q,)) #把实例化的队列传到子进程,通过这种方式实现进程间通信。而线程不需这么做。
    p.start()
    print(q.get())
    p.join()
    print("done")

原理是子进程复制了一份数据,然后通过序列化和反序列化再同步给主进程,不同于线程里面的修改数据

二、使用Pipes(管道)数据传递

# Author:Brownyangyang
from multiprocessing import Process,Pipe

def f(conn):
    conn.send([42,None,'hello'])  ##子进程给父进程发消息
    conn.send([40,'liyang','bye'])
    print(conn.recv())
    conn.close()

if __name__ == '__main__':
    parent_conn,clild_conn = Pipe() ##生成管道实例
    p = Process(target=f,args=(clild_conn,)) ##这个传哪个都行,也可以传parent_conn
    p.start()
    print(parent_conn.recv())
    print(parent_conn.recv())
    parent_conn.send('hahahhah')  ##父进程给子进程发消息
    p.join

三、managers 实现数据共享

# -*- coding:utf-8 -*-
# Author:Brownyangyang

from multiprocessing import Process,Manager
import os

def f(d,l):
    d[os.getpid()] = os.getpid()
    l.append(os.getpid())
    print(l)

if __name__ == '__main__':
    with Manager() as manager:
        d = manager.dict()  #生成一个字典,可在多个进程间共享和传递
        l = manager.list(range(5)) #生成一个列表,可在多个进程间共享和传递
        p_list = []
        for i in range(10):
            p = Process(target=f,args=(d,l))
            p.start()
            p_list.append(p)

        for res in p_list:
            res.join()

        print(d)
        print(l)

进程锁:虽然进程独立,但是屏幕对于进程是共享的,这个锁只是控制屏幕打印不出现混乱

# -*- coding:utf-8 -*-
# Author:Brownyangyang
from multiprocessing import Process,Lock

def f(lock,i):
    lock.acquire()
    print("process id",i)
    lock.release()

if __name__ == '__main__':
    lock = Lock()
    for i in range(10):
        p = Process(target=f,args=(lock,i,))
        p.start()

进程池

在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。
Pool可以提供指定数量的进程供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。

apply   同步
apply_async  异步
 
# -*- coding:utf-8 -*-
# Author:Brownyangyang
from multiprocessing import Process,Pool
import time,os
#import greenlet

def Foo(i):
    time.sleep(2)
    print("in process",os.getpid())
    return  i+10  ##这个参数会作为Bar的参数传递给Bar,这个不是很理解

def Bar(arg):
    print("-->exec done:",arg,os.getpid()) ##回调

if __name__ ==  '__main__':
    pool = Pool(processes=5) ##允许进程池同时放入5个进程
    print("主进程",os.getpid())
    for i in range(10):
        pool.apply_async(func=Foo,args=(i,),callback=Bar) #并行,执行完Foo就会执行Bar,这个Bar是主进程执行的,PID和主进程一样
        #pool.apply(func=Foo,args=(i,)) 串行

    print('end')
    pool.close()
    pool.join()##进程池中进程执行完毕后再关闭,如果注释则主程序执行完就退出。

这个callback为什么是主进程写而不是子进程写呢,因为主进程写数据库只要一个长连接,但是如果是子进程需要10个链接,无形拉低了代码效率

结果打印:
主进程 51590
end
in process 51592
in process 51593
in process 51591
in process 51594
in process 51595
-->exec done: 12 51590
-->exec done: 11 51590
-->exec done: 13 51590
-->exec done: 10 51590
-->exec done: 14 51590
in process 51593
in process 51592
in process 51594
in process 51591
in process 51595
-->exec done: 15 51590
-->exec done: 16 51590
-->exec done: 18 51590
-->exec done: 17 51590
-->exec done: 19 51590
 
原文地址:https://www.cnblogs.com/brownyangyang/p/8910868.html