文章根据网课整理的笔记,如有错误,请不吝赐教!
进程
进程介绍
进程的概念:进程(Process)是资源分配的最小单位,它是操作系统进行资源分配和调度运行的基本单位
,是动态的。例如正在运行的QQ,浏览器等。
一个程序运行后至少有一个进程。
那么,多进程有什么用呢?先看到一下程序。
def fun_A():
print('任务A')
def fun_B():
print('任务B')
fun_A()
fun_B()
运行这个程序,会按照代码的执行顺序,fun_A函数执行完毕以后才会执行fun_B函数。如果我们让fun_A和fun_B同时运行,那么这个效率显然会大大提升。而这也就是多进程。
进程的创建
-
导入进程包
import multiprocessing
-
通过进程类创建进程对象
进程对象 = multiprocessing.Process(target = 任务名)
- taget : 这里一般是指函数名,方法名
- name:进程名,一般不用设置
- group:进程组,目前只能使用None
-
启动进程执行任务
进程对象.start()
import time
import multiprocessing # 第一步,导入进程包
# 唱歌函数
def sing():
for i in range(3):
print('唱歌')
time.sleep(0.5) # 设置延迟
# 跳舞函数
def dance():
for i in range(3):
print('跳舞')
time.sleep(0.5)
if __name__ == '__main__':
# 使用进程类创建进程对象
sing_process = multiprocessing.Process(target=sing)
dance_process = multiprocessing.Process(target=dance)
# 启动
sing_process.start()
dance_process.start()
带参数的进程创建
传参有两种方式:
-
args: 以元组的方式传入,顺序一一对应,只有一个参数注意逗号(参数1,)
-
kwargs: 以字典的方式传入,顺序随意,但是key要和函数的参数名字一样
import time
import multiprocessing
def sing():
for i in range(3):
print('唱歌')
time.sleep(0.5)
def dance():
for i in range(3):
print('跳舞')
time.sleep(0.5)
if __name__ == '__main__':
# 使用进程类创建进程对象
sing_process = multiprocessing.Process(target=sing)
dance_process = multiprocessing.Process(target=dance)
# 启动
sing_process.start()
dance_process.start()
获取进程的编号
但程序越来越多时,不好区分进程的之间的关系,为了方便管理,我们需要获取进程编号。
有两种方式:
-
获取当前进程编号
os.getpid()
-
获取当前父进程的编号
os.getppid()
通俗的说,谁启动就是父进程,这里"main"是主进程,启动了两个子进程,sing_process和dance_process。
import time
import os
import multiprocessing # 第一步,导入进程包
# 唱歌函数
def sing(num):
print('我是唱歌进程:',os.getpid())
print('唱歌的父进程:', os.getppid())
for i in range(num):
print('唱歌')
time.sleep(0.5) # 设置延迟
# 跳舞函数
def dance(num):
print('我是跳舞进程:', os.getpid())
print('跳舞的父进程:', os.getppid())
for i in range(num):
print('跳舞')
time.sleep(0.5)
if __name__ == '__main__':
print('我是父进程:', os.getpid())
sing_process = multiprocessing.Process(target=sing,args=(2,))
dance_process = multiprocessing.Process(target=dance,kwargs={'num':1})
sing_process.start()
dance_process.start()
进程注意点:
- 主进程会等待所有子进程执行结束再结束
- 设置守护子进程
子进程对象.daemon = True
,主进程退出后子进程直接销毁。
案列:文件夹高并发copy器
线程
线程介绍
线程:线程是程序执行的最小单位。同一进程下的线程可以共享进程所拥有的全部资源。(进程是包工头,负责领取资源;线程是工人,负责干活)
线程创建对象
-
导入线程模块
import threading
- 通过线程类创建线程对象
threading.Thread(target=任务名)
- 启动线程执行任务
线程对象.start()
传参和进程是一样的,一并演示。
demo如下:
import time
import os
import threading
def sing(num):
for i in range(num):
print('唱歌')
time.sleep(0.5)
def dance(num):
for i in range(num):
print('跳舞')
time.sleep(0.5)
if __name__ == '__main__':
sing_thread = threading.Thread(target=sing,args=(5,))
dance_thread = threading.Thread(target=dance,kwargs={'num':4})
sing_thread.start()
dance_thread.start()
主线程和子线程的结束顺序
主线程会等待所有的子线程结束在结束
demo如下:
import time
import threading
def work():
for i in range(10):
print('工作....')
time.sleep(0.2)
if __name__ == '__main__':
sub_thread = threading.Thread(target=work)
sub_thread.start()
time.sleep(1)
print("主线程结束了") # 主线程其实没有结束,还在等待着子线程
设置守护主线程
-
创建时设置,如sub_thread = threading.Thread(target=work),daemon=True
import time
import threading
def work():
for i in range(10):
print('工作....')
time.sleep(0.2)
if __name__ == '__main__':
sub_thread = threading.Thread(target=work,daemon=True)
sub_thread.start()
time.sleep(1)
print("主线程结束了") # 因为子线程守护主线程,所以主线程和子线程这时候都乖乖结束
-
使用`线程对象.setDeamon(True)
import time
import threading
def work():
for i in range(10):
print('工作....')
time.sleep(0.2)
if __name__ == '__main__':
sub_thread = threading.Thread(target=work)
sub_thread.setDaemon(True)
sub_thread.start()
time.sleep(1)
print("主线程结束了")
线程的执行顺序
线程之间的执行的顺序是无序的
获取当前的线程信息
# 通过current_thread方法获取线程对象
current_thread = thread.current_thread()
# 通过current_thread对象可以知道线程的相关信息,例如创建顺序
print(current_thread)
进程和线程的对比
-
关系对比
- 线程是依附在进程里面的,没有进程就没有线程
- 一个进程默认提供一条线程,进程可以创建多个线程
-
区别
- 创建进程的资源开销要比创建线程的资源开销大
- 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
- 线程不能独立运行
-
优缺点对比
- 进程优缺点
- 线程优缺点
案例:高并发cpoy器
多进程高并发cpoy器
-
定义源文件夹所在的路径,目标文件夹所在的路径
source_dir = ""
dest_dir = ""
-
创建目标文件夹
try:
os.mkdir(dest_dir)
except:
print('目录已存在!')
-
通过os.listdir获取源目录的文件列表
file_list = os.listdir(source_dir)
# print(file_list)
-
遍历每个文件,定义一个函数,专门实现文件拷贝
for file_name in file_list:
copy_work(file_name,source_dir,dest_dir)
-
对4进行优化,采用进程多任务,完成高并发拷贝
for file_name in file_list:
copy_work(file_name,source_dir,dest_dir)
sub_process = multiprocessing.Process(target=copy_wrok,args=(file_name,source_dir,dest_dir))
sub_process.start()
最终代码
import multiprocessing
import os
def copy_work(file_name,source_dir,dest_dir):
# 拼接文件路径
source_path = source_dir + "/" + file_name
dest_path = dest_dir + "/" + file_name
# 打开源文件和目标文件
with open(source_path,"rb") as source_file:
with open(dest_path,"wb" ) as dest_file:
# 循环读取源文件到目标路径
while True:
data = source_file.read()
if data:
dest_file.write(data)
else:
break
if __name__ == "__main__":
# 定义源文件夹和目标文件夹
source_dir = "D:/test1"
dest_dir = "D:/test2"
# 创建目标文件夹
try:
os.mkdir(dest_dir)
except:
print('目录已存在!')
# 读取源文件夹的文件列表
file_list = os.listdir(source_dir)
print(file_list)
# 遍历文件列表实现拷贝
for file_name in file_list:
copy_work(file_name, source_dir, dest_dir)
sub_process = multiprocessing.Process(target=copy_work, args=(file_name, source_dir, dest_dir))
sub_process.start()