166 views
Python高级技巧

8.Python多任务-进程

文章目录

Python进程

1. 什么是程序?什么是进程?
进程:正在执行的程序(任务管理器里面看到的qq进程)
程序:没有执行的代码,是一个静态的(qq.exe文件)

子进程就是将父进程里面的代码复制一份

2. 使用进程实现多任务
multiprocessing模块就是跨平台的多进程模块,
提供了一个Process类来代表一个进程对象,
这个对象可以理解为是一个独立的进程,可以执行另外的事情。

3. 线程和进程之间的对比
进程:能够完成多任务,一台电脑上可以同时运行多个QQ
线程:能够完成多任务,一个QQ中的多个聊天窗口
根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位

4. 进程间通信-Queue
Queue-队列 先进先出

5. 队列间简单通信
模拟下载数据,与数据处理

6. 多进程共享全局变量
共享全局变量不适用于多进程编程

7. 进程池
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process,
动态生成多个进程,但是如果是上百甚至上千个目标,手动的去创建的进程的工作量巨大,
此时就可以用到multiprocessing模块提供的Pool方法

初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,
那么就会创建一个新的进程用来执行该请求,但是如果池中的进程数已经达到指定的最大值,
那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务

8. 进程的使用方法和线程差不多,只是将threading换成multiprocessing模块,但是他们之间也是有区别的
进程就像是一条流水线
线程就像流水线上面的每个人
生产量不够,多加一条流水线增加产量

Python队列,进程间通信(不是数据共享)

import multiprocessing,time
from multiprocessing import Queue
# put 往队列里面添加数据
# get 往队列里面提取数据

def demo1(qu):
    li = [11,22,33]
    for i in li:
        qu.put(i)   
    print('put ok')

def demo2(qu):
    while True:
        print(qu.get())
        if qu.empty():
            break
    print('get ok')

if __name__ == '__main__':
    qu=Queue(2) #队列里面的值设置成多大,队列就又多大,不设置,按需分配
    m1=multiprocessing.Process(target=demo1,args=(qu,))
    m2=multiprocessing.Process(target=demo2,args=(qu,))

    m1.start()
    m2.start()
---------------------
11
22
put ok
get ok

Python进程池示例

import os,time,random
from multiprocessing import Pool
# coding:utf8


def work(msg):
    print('{} 进程开始执行,进程id为: {}'.format(msg,os.getpid()))
    time.sleep(1)
if __name__ == '__main__':
    print('----start-----')
    # 1个进程池由4个进程组成,其中4个进程id是永远不变的,直至程序结束
    p=Pool(4)
    # 10个进程想要执行,需要排队,
    for i in range(0,10):
        p.apply_async(work,(i,))
    p.close()
    p.join()
    print('----end-------')
-----------------结果----------------------------
----start-----
0 进程开始执行,进程id为: 33636
1 进程开始执行,进程id为: 8220
2 进程开始执行,进程id为: 34116
3 进程开始执行,进程id为: 36820

4 进程开始执行,进程id为: 33636
5 进程开始执行,进程id为: 8220
6 进程开始执行,进程id为: 34116
7 进程开始执行,进程id为: 36820

8 进程开始执行,进程id为: 33636
9 进程开始执行,进程id为: 8220
----end-------

Python进程池间的进程通信

import os,time,random
import multiprocessing
# coding:utf8


def demo1(p):
    # 进程池里面的进程出现问题,不会主动跑出异常,最好加上try方法
    try:
        p.put('aaaaaaa')
    except Exception as e:
        print(e)
        exit(1)
def demo2(p):
    try:
        print(p.get())
    except Exception as e:
        print(e)
        exit(1)
if __name__ == '__main__':
    #进程池之间的进程通信,需要用该方法
    p=multiprocessing.Manager().Queue()
    po=multiprocessing.Pool(2)

    po.apply_async(demo1,args=(p,))
    po.apply_async(demo2,args=(p,))

    po.close()
    po.join()

Python进程文件夹复制(案例)

思路:
1 获取用户要copy的文件夹的名字
2 创建一个新的文件夹
3 获取文件夹的所有的待copy的文件名字
4 创建进程池
5 向进程池中添加拷贝任务

代码:
import multiprocessing
import os,time

"""
1 获取用户要copy的文件夹的名字
2 创建一个新的文件夹
3 获取文件夹的所有的待copy的文件名字
4 创建进程池
5 向进程池中添加拷贝任务
"""

def copy_file(name,new_file,old_file,q):

    print('拷贝的文件名:{}'.format(name))
    with open(old_file+'/'+name,'rb') as f:
        res=f.read()
    with open(new_file+'/'+name,'wb') as f:
        f.write(res)
    q.put(name)
def main():
    # 1.获取用户要copy的文件夹的名字
    old_file=input('请输入需要复制的文件夹名字:')
    # 2.创建一个新的文件夹
    new_file = old_file+'_bak'
    if not os.path.exists(new_file):
        os.mkdir(new_file)
    # 3.获取文件夹的所有的待copy的文件名字
    file_names=os.listdir(old_file)
    file_count=len(file_names)
    # 4.创建进程池
    po=multiprocessing.Pool(2)
    # 创建队列
    q=multiprocessing.Manager().Queue()

    for name in file_names:
        po.apply_async(copy_file,(name,new_file,old_file,q))
    po.close()

    copy_count=0
    while True:
        f=q.get()
        copy_count +=1
        print('\r进度:%2.f%%'%(copy_count*100/file_count))
        if copy_count >= file_count :
            break
if __name__ == '__main__':
    main()
---------------------------
请输入需要复制的文件夹名字:demo
拷贝的文件名:单线程.py
拷贝的文件名:线程锁.py
进度:25%
进度:50%
拷贝的文件名:进程池.py
拷贝的文件名:进程池间通信.py
进度:75%
进度:100%