1 进程的创建步骤
- 导入进程包
import multiprocessing- 通过进程类创建进程对象
process_obj = multiprocessing.Process()
- 启动进程执行任务
process_obj.start()
2 通过进程类创建进程对象
process_obj = multiprocessing.Process(target=task_name)
| 参数名 | 说明 |
|---|---|
| target | 执行的目标任务名,这里指的是函数名(方法名) |
| name | 进程名,一般不用设置 |
| group | 进程组,目前只能用None |
3 进程创建与启动的代码
import multiprocessing as mp# 创建子进程sing_p = mp.Process(target=sing)# 创建子进程dance_p = mp.Process(target=dance)# 启动进程sing_p.start()dance_p.start()
4 进程执行带有参数的任务
| 参数名 | 说明 |
|---|---|
| args=(value1,) | 以元组的方式给执行任务传递参数(传参一定要和函数参数顺序一致) |
| kwargs={“parameter1”:value1} | 以字典方式给执行任务传递参数 |
# 以元组 args
sing_p = multiprocessing.Process(target=sing,args=(3,'ck'))
# 以字典 kwargs={"parameter":value}
dance_p = multiprocessing.Process(target=dance,kwargs={'num':3,'name':'ck'})
5 获取进程编号
进程编号的作用:
当程序中进程的数量越来越多时,如果没有办法区分主进程和子进程还有不同的子进程。那么就无法有效进行进程管理。为了方便管理实际上每个进程都是由自己的编号的。
| 方法 | 作用 |
|---|---|
| os.getpid() | 获取当前进程编号 |
| os.getppid() | 获取当前父进程编号 |
@decorator_timer
def sing(num,name):
print(f'sing() pid == {os.getpid()}')
print(f'sing() ppid == {os.getppid()}')
for i in range(num):
print(f'{name} sing {i}...')
time.sleep(0.5)
@decorator_timer
def dance(num,name):
print(f'dance() pid == {os.getpid()}')
print(f'dance() ppid == {os.getppid()}')
for i in range(num):
print(f'{name} dance {i}...')
time.sleep(0.5)
子进程是并行执行的(同一时刻多进程同时执行)
因为循环外面的输出只在启动进程时调用了一次
__main__ pid == 5772
sing() pid == 5773
sing() ppid == 5772
ck sing 0...
dance() pid == 5774
dance() ppid == 5772
ck dance 0...
ck sing 1...
ck dance 1...
ck sing 2...
ck dance 2...
sing() has been running for "1.505s"...
dance() has been running for "1.503s"...
Process finished with exit code 0
6 进程的注意点
1 主进程会等待所有子进程执行结束后再结束
@decorator_timer
def work():
for i in range(5):
print(f'working...')
time.sleep(0.2)
print('work_p finished!')
if __name__ == '__main__':
work_p = multiprocessing.Process(target=work)
work_p.start()
# 主进程等待1s
time.sleep(0.5)
print('main process finished!')
从下面输出可以看出
- 子进程和主进程并行
- 主进程结束但子进程没有结束,此时不结束程序运行
- 最后所有的子进程结束后,程序结束运行
working...
working...
working...
main process finished!
working...
working...
work_p finished!
work() has been running for "1.003s"...
Process finished with exit code 0
2 设置子进程为守护进程——主进程结束即结束程序运行 .daemon=True
work_p = multiprocessing.Process(target=work,daemon=True)
# work_p.daemon = True
work_p.start()
主进程结束,子进程停止,程序运行结束
working...
working...
working...
main process finished!
多进程与装饰器的坑
7 利用多进程实现文件夹高并行copy
# -*- coding:utf-8 -*-
# @Time : 2020/9/2 10:38
# Author : chgken
# @File : mulpro_copy.py
# @Software : PyCharm
import time
import timeit
import multiprocessing
import os
import functools
def decorator_timer(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
t1 = timeit.default_timer()
func(*args,**kwargs)
t2 = timeit.default_timer()
print(f'{func.__name__} has been running for "{round(t2-t1,3)}s..."')
return func
return wrapper
class MultiCopy():
# 2. 读取源文件夹文件列表并多进程执行拷贝
@decorator_timer
def get_file_list(self,source_path ,destination_path):
try:
os.mkdir(destination_path)
except:
print('{self.destination_path} already existed!')
file_lsit = os.listdir(source_path)
# 3. 使用多进程实现多任务拷贝
for file in file_lsit:
sub_process = multiprocessing.Process(target=self.copy_file, args=(file,source_path,destination_path,))
sub_process.start()
# 3. 使用多进程实现多任务拷贝
@decorator_timer
def copy_file(self,file,source_path ,destination_path):
source_path = os.path.join(source_path,file)
destination_path = os.path.join(destination_path,file)
if os.path.isdir(source_path):
print(f'redirecte to {source_path}')
self.get_file_list(source_path,destination_path)
else:
with open(source_path,'rb') as sf:
with open(destination_path,'wb') as df:
while True:
read_data = sf.read(1024)
if read_data:
df.write(read_data)
else:
print(f'{source_path} copy done!')
return
if __name__ == '__main__':
# 1.定义目标文件夹和源文件夹地址
source_path = r'E:\学院资料'
destination_path = r'D:\桌面\学院资料_cp'
run = MultiCopy()
run.get_file_list(source_path,destination_path)
