python多线程编程笔记
资料:视频教程
时间:2021.8.31
一、进程
(一)、多任务介绍
多任务:同一时间内执行多个任务
多任务的好处:最大好处是充分利用cpu资源,提高程序的执行效率
两种方式
1、并发
2、并行
(二)、进程的介绍
进程是资源分配的最小单位,它是操作系统进行资源分配和调度运行的基本单位(eg:正在执行的程序就是一个进程)
(三)、多进程完成多任务
1、进程的创建步骤
-
导入进程包
-
import multiprocessing
-
-
通过进程类创建进程对象
-
进程对象 = multiprocressing.Process(target=任务名)
-
-
启动进程执行任务
-
进程对象.start()
-
#1、导入包
import multiprocessing
import time
def sing():
for i in range(3):
print("唱歌……")
time.sleep(0.3)
def dance():
for j in range(3):
print("跳舞……")
time.sleep(0.3)
if __name__ == '__main__':
#2、创建进程
process_sing = multiprocessing.Process(target=sing)
process_dance = multiprocessing.Process(target=dance)
#3、开启进程
process_dance.start()
process_sing.start()
2、进程执行带有参数的任务
注意:args传参要注意参数的先后顺序,kwargs传参要注意key的名字和参数名保持一致
#导入包
import multiprocessing
import time
def sing(num,name):
print("%s唱歌"%name)
for i in range(num):
print("唱歌%d……"%i)
time.sleep(0.3)
def dance(num):
for j in range(num):
print("跳舞%d……"%j)
time.sleep(0.3)
if __name__ == '__main__':
#创建进程
# target :任务名字
#args:以元组的方式给函数传参数
#kwargs:以字典的方式给函数传参数
#注意:args传参要注意参数的先后顺序,kwargs传参要注意key的名字和参数名保持一致
process_sing = multiprocessing.Process(target=sing,args=(3,"zqq"))
process_dance = multiprocessing.Process(target=dance,kwargs={"num":4})
#开启进程
process_dance.start()
process_sing.start()
(四)、获取进程编号
1、获取进程编号的两种方式
-
获取当前进程编号
os.getpid()
-
获取当前父进程编号
os.getppid()
2、使用方法
-
导包
import os
#导入包 import multiprocessing import time import os #唱歌 def sing(num,name): print("唱歌的进程pid",os.getpid()) #当前进程编号 print("唱歌的主进程pid",os.getppid()) #父进程编号 print("%s唱歌"%name) for i in range(num): print("唱歌%d……"%i) time.sleep(0.3) #跳舞 def dance(num): print("跳舞的进程pid",os.getpid()) print("跳舞的主进程pid",os.getppid()) for j in range(num): print("跳舞%d……"%j) time.sleep(0.3) if __name__ == '__main__': print("主进程的pid:%d\n"%os.getpid(),"------"*10) #创建进程 # target :任务名字 #args:以元组的方式给函数传参数 #kwargs:以字典的方式给函数传参数 #注意:args传参要注意参数的先后顺序,kwargs传参要注意key的名字和参数名保持一致 process_sing = multiprocessing.Process(target=sing,args=(3,"zqq")) process_dance = multiprocessing.Process(target=dance,kwargs={"num":4}) #开启进程 process_dance.start() process_sing.start()
(五)、进程的注意点
1、主进程会等待所有的子进程执行结束后再结束
eg:
import multiprocessing
import time
def work():
for i in range(10):
print("工作中……")
time.sleep(0.2)
if __name__ == '__main__':
work_process = multiprocessing.Process(target=work())
# work_process.daemon = True
work_process.start()
time.sleep(1)
print("主进程结束")
2、设置守护主进程(主进程)
进程对象.daemon = True
import multiprocessing
import time
def work():
for i in range(10):
print("工作中……")
time.sleep(0.2)
if __name__ == '__main__':
work_process = multiprocessing.Process(target=work())
#开始主线程守护,主线程结束其他线程也结束
work_process.daemon = True
work_process.start()
time.sleep(1)
print("主进程结束")
(六)、多任务的copy器
1、需求分析
- 目标文件夹是否存在,如果存在就不创建文件夹,不存在则创建文件夹
- 遍历源文件中所有文件,并拷贝到目标文件夹中
- 采用进程实现多任务,完成高并发拷贝
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: #rb 二进制方式读取文件内容
with open(dest_path,"wb") as dest_file: #wb 二进制方式写入文件内容
# 3、循环读取源文件到目标路径
while True:
data = source_file.read(1024)
if data:
dest_file.write(data)
else:
break
if __name__ == '__main__':
# 1、定义源文件和目标文件夹
source_dir = r"G:\markdown\python"
dest_dir = r"D:\python"
# 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_list, source_dir, dest_dir)
# 5、使用多进程实现多任务拷贝
process = multiprocessing.Process(target=copy_file,args=(file_name,source_dir,dest_dir))
process.start()
二、线程
(一)、线程的介绍
(二)、多线程完成多任务
1、线程的创建步骤
-
导入线程模块
import threading
-
创建线程对象
线程对象 = threading.Thread(target = 任务名)
-
启动线程执行任务
线程对象.start()
import time
import threading
def sing():
for i in range(3):
print("唱歌:",i)
time.sleep(1) #休息1s
def dance():
for j in range(3):
print("跳舞:",j)
time.sleep(1)
if __name__ == '__main__':
#sing()
#dance()
#创建线程
sing_thread = threading.Thread(target = sing)
dance_thread = threading.Thread(target = dance)
#开启线程
sing_thread.start()
dance_thread.start()
(三)、线程执行带有参数的任务
import time
import threading
def sing(num):
for i in range(num):
print("唱歌:",i)
time.sleep(1) #休息1s
def dance(num):
for j in range(3):
print("跳舞:",j)
time.sleep(1)
if __name__ == '__main__':
#创建线程
#args:传参到函数中要注意参数顺序,参数是元组的方式
#kwargs:以字典的方式进行传递,注意:参数名一定要与一致
sing_thread = threading.Thread(target = sing,args=(3,))
dance_thread = threading.Thread(target = dance,kwargs={"num":3})
#开启线程
sing_thread.start()
dance_thread.start()
(四)、主线程和子线程的结束顺序
主线程会等待所有的子线程执行结束后主线程再结束
设置守护进程的两种方式:
-
在创建线程时,加入daemon参数并为True
threading.Thread(target=任务名,daemon=True)
-
使用damon
线程对象.demon = True
import threading
import time
def work():
for i in range(10):
print("工作中……",i)
time.sleep(0.5)
if __name__ == '__main__':
work_thread = threading.Thread(target=work,daemon=True)
#方式一:设置守护线程
# work_thread.daemon = True
work_thread.start()
time.sleep(4)
print("主线程结束")
(五)、线程间的执行顺序
线程之间执行的顺序是无序的
-
获取当前的线程信息,通过current_thread方法
#通过current_thread()获取线程 current_thread = threading.current_thread() #打印 print(current_thread)
import threading import time def task(): time.sleep(1) thread = threading.current_thread() print(thread) if __name__ == '__main__': for i in range(5): sub_thread = threading.Thread(target=task) sub_thread.start() #执行是无序的
(六)、进程和线程的对比
- 关系对比
- 线程是依附在进程里面的,没有进程就没有线程
- 一个进程默认提供一条线程,进程可以创建多个线程
-
区别对比
- 创建进程的资源开销要比创建线程的资源开销要大
- 进程是操作系统资源分配的基本单位,线程是cpu调度的基本单位
- 线程不能够单独执行,必须依存在进程中
-
优缺点
(七)、多进程高并发的copy器
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: #rb 二进制方式读取文件内容
with open(dest_path,"wb") as dest_file: #wb 二进制方式写入文件内容
# 3、循环读取源文件到目标路径
while True:
data = source_file.read(1024)
if data:
dest_file.write(data)
else:
break
if __name__ == '__main__':
# 1、定义源文件和目标文件夹
source_dir = r"G:\markdown\python"
dest_dir = r"D:\python"
# 2、创建目标文件夹
try:
os.mkdir(dest_dir)
except:
print("目标文件已经存在了")
# 3、读取源文件的文件列表
file_list = os.listdir(source_dir)
# 4、遍历文件列表实现拷贝
for file_name in file_list:
thread = threading.Thread(target=copy_file,args=(file_name,source_dir,dest_dir))
thread.start()