python高级之多任务2(进程)

python高级之多任务2(进程)

3.3进程

3.3.1进程概述

通俗理解一个运行起来的程序或者软件叫做进程

(1)每次启动一个进程都需要向操作系统索要运行资源(内存),进程是操作系统资源分配的基本单位

(2)进程只提供运行资源,真正干活的是线程,线程是执行程序中对应的代码的, 默认一个进程默认只提供一个线程(主线程),当然还可以在一个进程里面开辟多个线程

(3) 如何理解进程:把公司类比成进程,公司会给我们提供办公资源(办公桌椅,办公电脑等),公司里面的员工利用公司里面的资源去干活,所以公司可以想成进程,员工就是线程

3.3.2进程和线程的对比

(1)进程是操作系统资源分配的基本单位,线程是cpu调度的基本单位,cpu调度哪个线程,哪个线程去执行对应的代码

(2)进程之间不共享全局变量, 线程之间共享全局变量,但是要注意资源竞争的问题,解决问题的方式是互斥锁或者线程同步

(3)多进程开发比单进程多线程开发代码的稳定性要强,但是多进程开发比多线程开发资源开销要多

(4)多进程开发某一个进程挂掉不会影响其它进程的运行,单进程开发该进程挂掉所有的线程都死掉了, 多线程开发会共享进程中资源

(5)先有进程,线程是依附在进程里面的,默认一个进程会提供一个线程(主线程)

3.3.3创建进程

import multiprocessing

sub_process = multiprocessing.Process(group=None, target=show_info, name=“myprocess”, args=(“杨钰莹”, 18))

sub_process.start()

参数说明:

(1)group: 进程组, 默认值必须是None

(2)target:执行的目标函数

(3)name: 进程名称, 如果不指定进程名字的格式: Process-1,…

(4)args: 以元组的方式传参

(5)kwargs:以字典的方式传参

3.3.4获取进程、进程编号

import  multiprocessing 
import os
def work():

# 获取当前进程

​    current_process = multiprocessing.current_process()print("work:", current_process)

# 扩展-获取进程编号print("work的进程编号:", current_process.pid, os.getpid())

# 获取父进程的编号print("work进程的父进程编号:", os.getppid())for i in range(10):print("工作中....")
​        time.sleep(0.2)

# 扩展: 根据进程编号杀死指定进程

​        os.kill(os.getpid(), 9)

3.3.5进程注意点

(1)进程之间不共享全局变量

(2)主进程等待子进程完成再退出

若不想主进程一直等待,可用:

①守护主进程

sub_process = multiprocessing.Process(target=test)

sub_process.daemon = True

time.sleep(1)

sub_process.start()

②销毁子进程

sub_process = multiprocessing.Process(target=test)

time.sleep(1)

sub_process.terminate()

sub_process.start()

3.3.6进程间通信——Queue

可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息队列(先进先出)程序

创建消息队列:

queue = multiprocessing.Queue()

说明:

(1)初始化Queue()对象时(例如:queue=Queue()),若括号中没有指

定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数

量没有上限(直到内存的尽头)

(2)放入数据:

queue.put(xxxx)

注意:消息队列可以放入任何数据类型。如果队列满了使用put放入

数据会等待,直到队列有空闲位置才能放入数据。如果队列满了使用

put_nowait不会等待,放入数据不成功会崩溃。 为了安全起见放入数

据统一使用put

(3)获取队列里的数据

value = queue.get()

print(value)

注意: 如果队列空了,那么使用get取值会等待,直到队列有数据才

能获取数据。如果队列空了, 使用get_nowait不会等待,如果取值不

成功则崩溃。为了安全起见获取数据使用get。

(4)获取队列的个数,注意:mac不能使用此方法

queue_size = queue.qsize()

(5)判断队列是否为空

queue.empty()——不靠谱

如果队列为空,返回True,反之False

注意:判断队列是否为空的时候,不会等数据全部写入到队列以

后再判断,有可能出现获取的队列是空的

解决办法:保证数据全部写入到队列里面以后再去做判断

① 延时

time.sleep(0.001)

②根据个数判断

if queue.qsize() == 0:

print(“队列为空”)

else:

print(“队列不为空”)

3.3.7进程池

池子里面放的都是进程,进程的创建是进程池根据执行任务的情况自动创建进程,进程池会合理利用现有的进程完成多任务

import multiprocessing
import time

##### 拷贝任务

def copy_work():
    print("复制中....,", multiprocessing.current_process().pid)

##### 默认进程池创建的进程是守护主进程,那么主进程退出进程池中的子进程就直接销毁

​    time.sleep(1)

 

if __name__ == '__main__':

# 创建进程池, 3:表示进程池中最大进程的个数

​    pool = multiprocessing.Pool(3)

# 使用进程池执行对应任务,默认大批量的复制任务让进程池帮我们完成for i in range(10):

# 同步执行对应的任务,是一个任务执行完成另外一个任务才能执行

# pool.apply(copy_work)

# 异步执行,多个任务一起执行,任务之间不会等待

​        pool.apply_async(copy_work)#注意:异步执行要有下面的操作:关闭进程池和等待

# 关闭进程池,表示进程池以后不再接收对应的任务了,主进程会根据现有进程池的任务执行完成以后程序就可以退出了

​    pool.close()

# 主进程等待进程池把任务执行完成以后程序再退出

​    pool.join()

##### 提醒: 进程池会根据任务执行情况自动创建进程,进程池会尽量少创建进程,可以利用现有的进程完成多任务

3.3.8进程池中的Queue

(1)如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue()

(2)创建进程池中queue

queue = multiprocessing.Manager().Queue(3)

(3)使用同步的方式执行任务

参数要使用元组传参

pool.apply(write_data, (queue, ))

(4)使用异步的方式去执行任务 ,异步执行任务会返回一个ApplyResult 对象

result = pool.apply_async(write_data, (queue,))

print(result)

(5)扩展:主进程等待异步任务执行完成以后代码再继续往下执行

result.w·ait()

pool.apply_async(read_data, (queue,))

异步执行任务,主进程需要等待进程池执行完成以后程序再退出

pool.close()

pool.join()

3.3.9案例:文件夹拷贝器

import os
import shutil
import multiprocessing
import time

# 拷贝文件的任务

def copy_work(src_dir, dst_dir, file_name):
    print(multiprocessing.current_process().pid)
    # 源文件的路径
    src_file_path = src_dir + "/" + file_name
    # 目标文件的路径
    dst_file_path = dst_dir + "/" + file_name
    # 打开目标文件
    with open(dst_file_path, "wb") as dst_file:
        # 打开源文件获取源文件的数据把数据写入到目标文件里面
        with open(src_file_path, "rb") as src_file:
            while True:
                # 读取数据
                src_file_data = src_file.read(1024)
                if src_file_data:
                    # 把源文件的数据写入到目标文件里面
                    dst_file.write(src_file_data)
                else:
                    break
    time.sleep(0.5)
if __name__ == '__main__':
    # 源目录
    src_dir = "test"
    # 目标目录
    dst_dir = "/home/python/Desktop/test"

##### 判断文件夹是否存在

if os.path.exists(dst_dir):

##### 删除目标目录

​    shutil.rmtree(dst_dir)

##### 创建文件夹

os.mkdir(dst_dir)

##### 获取源目录的文件列表

file_name_list = os.listdir(src_dir)

##### 创建进程池

pool = multiprocessing.Pool(3)

##### 遍历文件列表获取对应的文件名

for file_name in file_name_list:

##### 使用进程池完成多任务的文件拷贝

​    pool.apply_async(copy_work, (src_dir, dst_dir, file_name))

##### 关闭进程池

pool.close()

##### 主进程等待进程池执行完成以后程序再退出

pool.join()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值