目录
- 1, 多任务的概念
- 2,进程
- 2.1进程的介绍
- 2.2多进程完成多任务
- 2.3进程执行带有参数的任务
- 2.4获取进程编号
- 2.5进程间不共享全局变量
- 2.6主进程和子进程的结束顺序
- 3、线程
- 3.1多线程完成多任务
- 3.2线程执行带有参数的任务
- 3.3主线程和子线程的结束顺序
- 3.4线程中的执行顺序
- 3.5线程间共享全局变量
- 3.6线程间共享全局变量数据出现错误问题
- 3.7 互斥锁
- 3.8死锁
- 3.9进程和线程的对比
下载时多个一起下载 --多任务
多任务的最大好处:充分利用CPU资源,提高程序的执行效率
1, 多任务的概念
多任务是指同一时间内执行多个任务
两种表现形式:并发 ,并行
- 并发:一段时间内交替去执行多个任务
并发:任务数量大于CPU的核心数 - 并行:在一段时间内真正的同时一起执行多个任务
并行:任务数量小于等于CPU的核心数
2,进程
2.1进程的介绍
进程是资源分配的最小单位,它是操作系统进行资源分配和调度运行的基本单位,通俗理解:一个正在运行的程序就是一个进程。
例如:正在运行的qq,微信等,
微信在没有运行时,只是一个软件,当运行后,会变成占cpu资源,内存资源的进程
进程是资源分配的最小单位
多进程是python程序中实现多任务的一种方式,使用多进程可以大大提高程序的执行效率
2.2多进程完成多任务
进程的创建步骤:
1,导入进程包
import multiprocessing
2,通过进程类创建进程对象
进程对象 = multiprocessing.Process()
3,启动进程执行任务
进程对象.start()
进程对象 = multiprocessing.Process(target=任务名)
#单任务:先coding再music
import time
#编写代码
def coding():
for i in range(3):
print('coding...')
time.sleep(0.2) #停顿0.2秒
#听音乐
def music():
for i in range(3):
print('music...')
time.sleep(0.2) #停顿0.2秒
if __name__ =='__main__':
coding()
music()
输出:先打印三次coding后再打印三次music
多进程:三步。进程明显变快
#多进程
import multiprocessing
import time
#编写代码
def coding():
for i in range(3):
print('coding...')
time.sleep(0.2) #停顿0.2秒
#听音乐
def music():
for i in range(3):
print('music...')
time.sleep(0.2) #停顿0.2秒
if __name__ =='__main__':
#通过进程类创建进程对象
coding_process = multiprocessing.Process(target=coding)
music_process = multiprocessing.Process(target=music)
#启动进程
coding_process.start()
music_process.start()
2.3进程执行带有参数的任务
import multiprocessing
import time
#编写代码
def coding(num):
for i in range(num,name):
print(name)
print('coding...')
time.sleep(0.2) #停顿0.2秒
#听音乐
def music(count):
for i in range(count):
print('music...')
time.sleep(0.2) #停顿0.2秒
if __name__ =='__main__':
#通过进程类创建进程对象
coding_process = multiprocessing.Process(target=coding,args=(3,'传智'))
#传参args=(3,)元组
music_process = multiprocessing.Process(target=music,kwargs={'count':2})
#启动进程
coding_process.start()
music_process.start()
传参两种方式:
1,元组方式传参。顺序要保持一致
2,字典方式传参。key与参数名保持一致
2.4获取进程编号
进程数量越来越多,进行编号来进行管理
获取当前进程标号:getpid()方法
获取当前父进程编号:getppid()方法
import multiprocessing
import time
import os
def coding():
print('coding>>>%d' % os.getpid())
print('coding父进程>>>%d' % os.getppid())
for i in range(3):
print('coding...')
time.sleep(0.2) #停顿0.2秒
#听音乐
def music():
print('music>>>%d' % os.getpid())
print('music父进程>>>%d' % os.getppid())
for i in range(3):
print('music...')
time.sleep(0.2) #停顿0.2秒
if __name__ =='__main__':
print('主进程>>>%d' % os.getpid())
#通过进程类创建进程对象
coding_process = multiprocessing.Process(target=coding)
music_process = multiprocessing.Process(target=music)
#启动进程
coding_process.start()
music_process.start()
2.5进程间不共享全局变量
进程间是不共享全局变量的
创建一个子进程就是把主进程的资源进行拷贝产生了一个新的进程,而主程序和子程序之间是相互独立的
import multiprocessing
#全局变量
my_list = []
#写入数据
def write_data():
for i in range(3):
my_list.append(i)
print('add:',i)
print(my_list)
#读取数据
def read_data():
print(my_list)
if __name__ =='__main__':
#创建写入数据进程
write_process = multiprocessing.Process(target=write_data)
#创建读取数据进程
read_process = multiprocessing.Process(target=read_data)
#启动
write_process.start()
read_process.start()
写入进程中my_list不为空,但读入进程中的my_list还为空
2.6主进程和子进程的结束顺序
主进程会等待所有子进程执行结束后再结束
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.start()
#延时1秒
time.sleep(1)
print('主进程执行完毕')
虽然输出如此,但是还是在子进程结束后,主进程才结束
如何才能确保主进程最后执行:法一:守护主进程,法二:手动结束子进程
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()
#延时1秒
time.sleep(1)
#work_process.terminate() #手动结束子进程
print('主进程执行完毕')
3、线程
线程是程序执行的最小单位
同属一个进程的多个线程共享进程所拥有的全部资源
3.1多线程完成多任务
线程的创建步骤:
1,导入线程模块 import threading
2,通过线程类创建线程对象 线程对象 = ‘threading.Thread(target=任务名)’
3,启动线程执行任务 线程对象.start()
import threading
import time
#编写代码
def coding():
for i in range(3):
print('coding...')
time.sleep(0.2) #停顿0.2秒
#听音乐
def music():
for i in range(3):
print('music...')
time.sleep(0.2) #停顿0.2秒
if __name__ =='__main__':
#创建子线程
coding_process = threading.Thread(target=coding)
music_process = threading.Thread(target=music)
#启动子线程
coding_thread.start()
music_thread.start()
输出:两个同时在运行,且时间更少
3.2线程执行带有参数的任务
import multiprocessing
import time
#编写代码
def coding(num):
for i in range(num,name):
print(name)
print('coding...')
time.sleep(0.2) #停顿0.2秒
#听音乐
def music(count):
for i in range(count):
print('music...')
time.sleep(0.2) #停顿0.2秒
if __name__ =='__main__':
#通过进程类创建进程对象
coding_thread = threading.Thread(target=coding,args=(3,'传智'))
#传参args=(3,)元组
music_thread = threading.Thread(target=music,kwargs={'count':2})
#启动进程
coding_thread.start()
music_thread.start()
3.3主线程和子线程的结束顺序
主线程会等待所有的子线程执行结束后主线程再结束
import threading
import time
#工作函数
def work():
for i in range(10):
print('工作中。。')
time.sleep(0.2)
if __name__ =='__main__':
#创建写入数据进程
work_process = threading.Thread(target=work)
work_process.start()
#延时1秒
time.sleep(1)
print('主进程执行完毕')
输出表明:主线程完毕后,子线程还在执行
解决方法:1,参数方式设置守护主线程 2,子线程自动销毁
import threading
import time
#工作函数
def work():
for i in range(10):
print('工作中。。')
time.sleep(0.2)
if __name__ =='__main__':
#创建写入数据进程
#方式1:参数方式设置守护主线程daemon=True
#work_process = threading.Thread(target=work,daemon=True)
work_process = threading.Thread(target=work)
#方式2:
#work_thread.setDaemon(True)
work_process.start()
#延时1秒
time.sleep(1)
print('主进程执行完毕')
这样设置的目的:让主线程退出后子线程销毁,不让主线程再等待子线程去执行
3.4线程中的执行顺序
线程之间执行是无序的,是由CPU调度决定某个线程先执行的。并非先创建的先执行
3.5线程间共享全局变量
多个线程是在同一个进程中,多个线程使用的资源是同一个进程中的资源,因此多线程间是共享全局变量。
import multiprocessing
#全局变量
my_list = []
#写入数据
def write_data():
for i in range(3):
my_list.append(i)
print('add:',i)
print('write:',my_list)
#读取数据
def read_data():
print('read',my_list)
if __name__ =='__main__':
#创建写入数据进程
write_thread = threading.Thread(target=write_data)
#创建读取数据进程
read_thread = threading.Thread(target=read_data)
#启动
write_thread.start()
time.sleep(1)
read_thread.start()
读取和写入的是一样的,说明线程间共享全局变量
3.6线程间共享全局变量数据出现错误问题
#全局变量
g_num = 0
#对g_num进行加操作
def sum_num1():
for i in range(1000000):
global g_num
g_num+=1
print('g_num1:',g_num)
#对g_num进行加操作
def sum_num2():
for i in range(1000000):
global g_num
g_num+=1
print('g_num2:',g_num)
if __name__ =='__main__':
sum1_thread = threading.Thread(target=sum_num1)
sum2_thread = threading.Thread(target=sum_num2)
sum1_thread.start()
sum2_thread.start()
输出结果混乱,不是,g_num1:1000000;g_num2:2000000
解决方法:
使用线程同步:保证同一时刻只能有一个线程去操作全局变量
多线程同时操作全局变量可能会导致数据出现错误问题,可以使用线程同步方式来解决这个问题(互斥锁)
3.7 互斥锁
互斥锁:对共享数据进行锁定,保证同一时刻只有一个线程去操作
互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到锁的线程先等等,等锁使用完释放后,再其余线程去抢这个锁
步骤:
1,互斥锁创建
mutex = threading.Lock()
2,上锁
mutex.acquire()
3,释放锁
mutex.release()
#全局变量
g_num = 0
#对g_num进行加操作
def sum_num1():
#上锁
mutex.acquire()
for i in range(1000000):
global g_num
g_num+=1
#解锁
mutex.release()
print('g_num1:',g_num)
#对g_num进行加操作
def sum_num2():
#上锁
mutex.acquire()
for i in range(1000000):
global g_num
g_num+=1
#解锁
mutex.release()
print('g_num2:',g_num)
if __name__ =='__main__':
#创建锁
mutex = threading.Lock()
sum1_thread = threading.Thread(target=sum_num1)
sum2_thread = threading.Thread(target=sum_num2)
sum1_thread.start()
sum2_thread.start()
输出结果正常了
3.8死锁
死锁:一直等待对方释放锁的情景
#全局变量
g_num = 0
#对g_num进行加操作
def sum_num1():
#上锁
print('sum_num1...')
mutex.acquire()
for i in range(1000000):
global g_num
g_num+=1
print('g_num1:',g_num)
#对g_num进行加操作
def sum_num2():
#上锁
print('sum_num2...')
mutex.acquire()
for i in range(1000000):
global g_num
g_num+=1
print('g_num2:',g_num)
if __name__ =='__main__':
#创建锁
mutex = threading.Lock()
sum1_thread = threading.Thread(target=sum_num1)
sum2_thread = threading.Thread(target=sum_num2)
sum1_thread.start()
sum2_thread.start()
sum_num1和sum_num2没有释放锁的步骤,导致死锁
3.9进程和线程的对比
关系对比:
- 线程是依附在进程里面的,没有进程就没有线程
- 一个进程默认提供一条主线程,但可以提供多个子线程
进程和线程的区别对比:
进程优缺点:优:可以多核(即可以同时运行QQ和微信,此时是并行) 缺:资源开销大
线程优缺点:优:资源开销大;缺:不能使用多核(不能并行,只能并发,排队等待)