多线程
多任务
多任务指的是同一时间内执行多个任务
多任务有两种表现形式:
- 并发
- 并行
并发:在一段时间内交替去执行多个任务
并行:在一段时间内真正的同时一起执行多个任务
多任务的作用:充分利用CPU的资源,提高程序执行效率
进程
概述
进程(Process)是资源分配的最小单元,它是操作系统进行资源分配和调度运行的基本单元
通俗理解:一个正在运行的程序就是一个进程
进程的作用
可以使用多进程的方式去完成多任务
进程创建步骤
1、导入进程包
import multiprocessing
2、通过进程类创建进程对象
进程对象 = multiprocessing.Process(target=任务名[,name=进程名,group=进程组,目前只能使用None])
3、启动进程执行任务
进程对象.start()
代码部分--单任务
"""
@time:2022-03-29
@desc:
进程的单任务
分别执行唱歌和跳舞
"""
import time
# 唱歌
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()
dance()
结果输出:
代码部分--多进程实现多任务
"""
@time:2022-03-29
@desc:
同时执行唱歌,跳舞
多进程三步骤:
1、导入进程包
2、使用进程类创建进程对象
3、进程对象启动进程执行指定的任务
"""
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 | 以元组的方式给执行任务传参 |
kwargs | 以字典方式给执行任务传参 |
代码部分
"""
@time:2022-03-29
@desc:
"""
import time
# 导入进程包
import multiprocessing
# 唱歌
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__':
# 使用进程类创建创建进程对象
# args=(5,) 中的5会传递给sing(num)中的num
sing_process = multiprocessing.Process(target=sing, args=(3,))
# kwargs={"num": 5} 中的5会传递给dance(num)中的num
dance_process = multiprocessing.Process(target=dance,kwargs={"num": 2})
# 使用进程对象启动进程执行指定任务
sing_process.start()
dance_process.start()
结果输出:
获取进程的编号
进程编号的作用
当程序中的进程数量越来越多时,如果没有办法区分主进程和子进程还有不同的子进程,那么就无法进行有效的进程管理,为了方便管理实际上每个进程都是有自己的编号
获取进程编号的两种方法
- 获取当前进程编号
os.getpid()
- 获取当前父进程编号
os.getppid()
代码部分
"""
@time:2022-03-29
@desc:
获取进程编号
"""
import time
import multiprocessing
import os
# 唱歌
def sing():
print("sing父进程:", os.getppid())
print("唱歌进程PID:", os.getpid())
for i in range(3):
print("唱歌...")
time.sleep(0.5)
# 跳舞
def dance():
print("dance父进程:", os.getppid())
print("跳舞进程PID:", os.getpid())
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()
结果输出:
注意事项
1、默认情况下,主进程会等待所有的子进程执行结束再结束
代码部分
"""
@time:2022-03-29
@desc:
主进程会等待所有的子进程执行结束再结束
"""
import time
import multiprocessing
# 工作子进程
def work():
for i in range(10):
print("子进程工作中...")
time.sleep(0.5)
if __name__ == '__main__':
work_processing = multiprocessing.Process(target=work)
work_processing.start()
# 主进程
time.sleep(1)
print("主进程执行完成!")
结果输出:
2、设置守护主进程
为了保证子进程能够正常的运行,主进程会等待所有的子进程执行结束之后再销毁,设置守护进程的目的是主进程退出子进程销毁,不让主进程再等待子进程去执行
简而言之,守护主进程结束, 子进程不再执行剩余的代码
设置守护主进程的方式:子进程对象.daemon=True
代码部分
"""
@time:2022-03-29
@desc:
守护主进程:主进程结束,则不再执行子进程
"""
import time
import multiprocessing
# 工作子进程
def work():
for i in range(10):
print("子进程工作中...")
time.sleep(0.5)
if __name__ == '__main__':
work_processing = multiprocessing.Process(target=work)
# 设置守护主进程,主进程退出后子进程直接销毁,不再执行子进程中剩余的代码
work_processing.daemon = True
work_processing.start()
# 主进程
time.sleep(1)
print("主进程执行完成!")
结果输出:
案例
代码部分
import os
import multiprocessing
def copy_file(file_name, source_dir, dest_dir):
# 1 拼接源文件路径和目标文件路径
source_path = source_dir + '\\' + file_name
dest_path = dest_dir + '\\' + file_name
# 2 打开源文件和目标文件
with open(source_path, 'rb') as source_file:
with open(dest_path, 'wb') as dest_file:
# 3 循环读取源文件到目标路径
while True:
data = source_file.read(1024)
if data:
dest_file.write(data)
else:
break
if __name__ == '__main__':
# 1 定义源文件夹和目标文件夹
source_dir = r'F:\迅雷下载\视频-智能机器人从0到1系统入门课程\视频'
dest_dir= r'F:\目标文件夹'
# 2.创建目标文件夹
try:
os.mkdir(dest_dir)
except:
print("目标文件夹已经存在")
# 3.读取源文件夹的文件列表
file_list = os.listdir(source_dir)
# 4.遍历文件列表实现拷贝
for file_name in file_list:
# copy_file(file_name, source_dir, dest_dir)
# 5.使用多进程实现多任务拷贝
sub_process = multiprocessing.Process(target=copy_file, args=(file_name, source_dir, dest_dir))
sub_process.start()
线程
概述
进程是分配资源的最小单元,一旦创建了进程就会分配一定的资源
线程是程序执行的最小单元,实际上进程只负责分配资源,而利用这些资源执行程序的是线程
也就是说,进程是线程的容器,一个进程中最少有一个线程来负责执行程序,同时线程自己不拥有系统资源,只需要一点在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源
多线程作用
提高效率
线程的创建步骤
1、导入线程模块
import threading
2、通过线程类创建线程对象
线程对象 = threading.Thread(target=函数名[,name = 线程名,group=线程组,目前只能使用None])
3、启动线程执行任务
线程对象.start()
代码部分--单任务
"""
@time:2022-03-29
@desc:
单任务
"""
import time
# 唱歌
def sing():
for i in range(5):
print("唱歌...")
time.sleep(0.5)
# 跳舞
def dance():
for i in range(5):
print("跳舞...")
time.sleep(0.5)
if __name__ == '__main__':
sing()
dance()
结果输出:
代码部分--多任务
"""
@time:2022-03-29
@desc:
多线程实现多任务
"""
import time
import threading
# 唱歌
def sing():
for i in range(5):
print("唱歌...")
time.sleep(0.5)
# 跳舞
def dance():
for i in range(5):
print("跳舞...")
time.sleep(0.5)
if __name__ == '__main__':
# 创建线程对象
sing_thread = threading.Thread(target=sing)
dance_thread = threading.Thread(target=dance)
# 启动线程
sing_thread.start()
dance_thread.start()
结果输出:
执行带有参数的任务
参数说明
参数名 | 说明 |
---|---|
args | 以元祖的形式给执行任务传参 |
kwargs | 以字典的形式给执行任务传参 |
代码部分
"""
@time:2022-03-29
@desc:
带有传参的任务
"""
import time
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=(3,))
# 以字典的方式传参
dance_thread = threading.Thread(target=dance, kwargs={"num": 4})
# 启动线程
sing_thread.start()
dance_thread.start()
结果输出:
主线程与子线程的结束顺序
1、默认情况下,主线程会等待所有的子线程执行结束之后主线程再结束
代码部分
"""
@time:2022-03-29
@desc:
主线程与子线程的结束顺序
主线程会等待所有的子线程执行结束再结束
"""
import time
import threading
# word函数
def work():
for i in range(5):
print("工作中...")
time.sleep(0.5)
if __name__ == '__main__':
work_thread = threading.Thread(target=work)
work_thread.start()
time.sleep(1)
print("主线程结束...")
结果输出:
2、设置守护主线程
主线程结束子线程自动销毁
方法:线程对象 = threading.Thread(target=函数名,daemon=True)
或者 线程对象.setDaemon(True)
代码部分
"""
@time:2022-03-29
@desc:
设置守护主线程
主线程结束 子线程自动销毁
"""
import time
import threading
# word函数
def work():
for i in range(5):
print("工作中...")
time.sleep(0.5)
if __name__ == '__main__':
# 方法一:
# work_thread = threading.Thread(target=work, daemon=True)
# 方法二:
work_thread = threading.Thread(target=work)
work_thread.setDaemon(True)
work_thread.start()
time.sleep(1)
print("主线程结束...")
结果输出:
线程间的执行顺序
线程之间的执行顺序是无序的,由CPU调度
代码部分
"""
@time:2022-03-29
@desc:
线程间执行顺序
"""
import threading
import time
def task():
time.sleep(1)
# current_thread 获取当前线程的线程对象
thread = threading.current_thread()
print(thread)
if __name__ == '__main__':
for i in range(5):
sub_thread = threading.Thread(target=task)
sub_thread.start()
结果输出:
进程与线程的对比
关系对比
- 线程是依附在进程里面的,没有进程就没有线程
- 一个进程默认提供一条线程,进程可以创建多个线程
区别对比
- 创建进程的资源开销要比创建线程的资源开销要大
- 进程是操作系统资源分配的基本单元,线程是CPU调度的基本单元
- 线程不能独立运行,必须依附在进程中
优缺点对比
1、进程的优缺点
优点:可以用多核
缺点:资源开销大
2、线程优缺点
优点:资源开销小
缺点:不能使用多核
案例
import os
import threading
def copy_file(file_name, source_dir, dest_dir):
# 1 拼接源文件路径和目标文件路径
source_path = source_dir + '\\' + file_name
dest_path = dest_dir + '\\' + file_name
# 2 打开源文件和目标文件
with open(source_path, 'rb') as source_file:
with open(dest_path, 'wb') as dest_file:
# 3 循环读取源文件到目标路径
while True:
data = source_file.read(1024)
if data:
dest_file.write(data)
else:
break
if __name__ == '__main__':
# 1 定义源文件夹和目标文件夹
source_dir = r'F:\迅雷下载\视频-智能机器人从0到1系统入门课程\视频'
dest_dir= r'F:\目标文件夹'
# 2.创建目标文件夹
try:
os.mkdir(dest_dir)
except:
print("目标文件夹已经存在")
# 3.读取源文件夹的文件列表
file_list = os.listdir(source_dir)
# 4.遍历文件列表实现拷贝
for file_name in file_list:
# copy_file(file_name, source_dir, dest_dir)
# 5.使用多线程实现多任务拷贝
sub_thread = threading.Thread(target=copy_file, args=(file_name, source_dir, dest_dir))
sub_thread.start()
本文系作者 @小白学安全 原创发布在 xbxaq.com 站点,未经许可,禁止转载!
评论