Python多任务编程
创始人
2024-02-01 07:31:30

1.进程与多任务

1. 1 多任务的介绍

1.使用多任务能充分利用CPU资源,提高程序的执行效率,让程序具备处理多任务的能力。

2.多任务执行方式有两种:

并发:在一段时间内交替执行多个任务。

并行:在一段时间内真正的同时一起执行多个任务。

1.2 进程的介绍

1.进程(Process)是资源分配的最小单位。

2.多进程是Python程序中实现多任务的一种方式,使用多进程可以大大提高程序的执行效率。

1.3 多进程完成多任务

1.导入进程包。

2.创建子进程并指定执行的任务。

3.启动进程执行任务。

# 导入进程模块
import multiprocessing
import time# 敲代码
def coding():for i in range(3):print("coding...")time.sleep(0.2)# 听音乐
def music():for i in range(3):print("music...")time.sleep(0.2)if __name__ == '__main__':# coding()# music()# 通过进程类创建进程对象coding_process = multiprocessing.Process(target=coding)music_process = multiprocessing.Process(target=music)# 启动进程coding_process.start()music_process.start()

1.4 进程执行带有参数的任务

进程执行带有参数的任务有两种方式:

1.元组方式传参:元组方式传参一定要和参数的顺序保持一致。

2.字典方式传参:字典方式传参字典中的key一定要和参数名保持一致。

# 导入进程模块
import multiprocessing
import time# 敲代码
def coding(num,name):for i in range(num):print(name)print("coding...")time.sleep(0.2)# 听音乐
def music(count):for i in range(count):print("music...")time.sleep(0.2)if __name__ == '__main__':# coding()# music()# 通过进程类创建进程对象coding_process = multiprocessing.Process(target=coding,args=(3,"zs"))music_process = multiprocessing.Process(target=music,kwargs={"count":2})# 启动进程coding_process.start()music_process.start()

1.5 获取进程编号

1.获取当前进程编号

os.getpid()

2.获取当前父进程编号

os.getppid()

# 导入进程模块
import multiprocessing
import os
import time# 敲代码
def coding():# 获取coding_process的编号print("coding_process>>>%d" % os.getpid())# 获取coding_process的父进程的编号print("coding_process的父进程>>>%d" % os.getppid())for i in range(3):print("coding...")time.sleep(0.2)# 听音乐
def music():# 获取music_process的编号print("music_process>>>%d" % os.getpid())# 获取music_process的父进程的编号print("music_process的父进程>>>%d" % os.getppid())for i in range(3):print("music...")time.sleep(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()

两个子进程的父进程的编号与主进程的编号相同,证明两个子进程是由该父进程创建并启动的。

1.6 进程间不共享全局变量

  • 创建子进程会对主进程资源进行拷贝,也就是子进程就是主进程的一个副本。
  • 进程间不共享全局变量,因为操作的不是同一个进程里面的全局变量,只不过不同进程里面的全局变量名字相同而已。
import multiprocessing
import time# 全局变量
my_list = []# 写入数据
def write_data():for i in range(3):my_list.append(i)print("add:",i)print("write_data:",my_list)# 读取数据
def read_data():print("read_data:",my_list)if __name__ == '__main__':# 创建写入数据进程write_process = multiprocessing.Process(target=write_data)# 创建读取数据进程read_process = multiprocessing.Process(target=read_data)# 启动进程,执行任务write_process.start()time.sleep(1)read_process.start()

写入数据进程和读取数据进程不共享my_list这个全局变量。 

1.7 主进程和子进程的结束顺序

默认情况下,为了保证子进程能够正常的运行,主进程会等待所有的子进程执行完后再结束。

如果想要让主进程结束后子进程就销毁,可以采取以下两种方式:

  • 设置守护主进程方式:子进程对象.daemon = True
  • 销毁子进程方式:子进程对象.terminate()
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("主进程执行完毕")

2. 线程与多任务

2.1 线程的介绍

1.多线程是Python程序中实现多任务的一种方式。

2.线程是程序执行的最小单位。

3.同属一个进程的多个线程共享进程所拥有的全部资源。

2.2 多线程完成多任务

1.导入线程模块

2.创建子线程

3.启动线程执行任务

import time
import threading# 敲代码
def coding():for i in range(3):print("coding...")time.sleep(0.2)# 听音乐
def music():for i in range(3):print("music...")time.sleep(0.2)if __name__ == '__main__':# 创建子线程coding_thread = threading.Thread(target=coding)music_thread = threading.Thread(target=music)# 启动线程执行任务coding_thread.start()music_thread.start()

2.3 线程执行带有参数的任务

线程执行带有参数的任务有两种方式:

1.元组方式传参:元组方式传参一定要和参数的顺序保持一致。

2.字典方式传参:字典方式传参字典中的key一定要和参数名保持一致。

import time
import threading# 敲代码
def coding(num):for i in range(num):print("coding...")time.sleep(0.2)# 听音乐
def music(count):for i in range(count):print("music...")time.sleep(0.2)if __name__ == '__main__':# 创建子线程coding_thread = threading.Thread(target=coding,args=(3,))music_thread = threading.Thread(target=music,kwargs={"count" : 2})# 启动线程执行任务coding_thread.start()music_thread.start()

2.4 主线程和子线程的结束顺序

默认情况下,为了保证子线程够正常的运行,主线程会等待所有的子线程执行完后再结束。

如果想要让主线程结束后子线程就销毁,可以采取以下两种方式:

  • 方式一:参数方式设置守护主线程
  • 方式二:方法方式设置守护主线程
import time
import threading# 工作函数
def work():for i in range(10):print("work...")time.sleep(0.2)if __name__ == '__main__':# 创建线程# 方式一:参数方式设置守护主线程# work_thread = threading.Thread(target=work,daemon=True)work_thread = threading.Thread(target=work)# 方式二:方法方式设置守护主线程work_thread.setDaemon(True)# 启动线程执行任务work_thread.start()# 延时1秒time.sleep(1)print("主线程执行完毕")

2.5 线程间的执行顺序

 线程之间执行是无序的,是由CPU调度决定某个线程先执行的。

import threading
import time# 获取线程信息函数
def get_info():time.sleep(0.5)# 获取线程信息current_thread = threading.current_thread()print(current_thread)if __name__ == '__main__':for i in range(10):# 创建子线程sub_thread = threading.Thread(target=get_info)# 启动线程执行任务sub_thread.start()

2.6 线程间共享全局变量

import threading
import time# 全局变量
my_list = []# 写入数据
def write_data():for i in range(3):my_list.append(i)print("add:",i)print("write_data:",my_list)# 读取数据
def read_data():print("read_data:",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()

线程间共享my_list这个共享变量。

2.7 线程间资源竞争问题

多线程同时操作全局变量可能会导致数据出现错误,可以使用线程同步方式来解决这个问题。

线程同步方式:

  • 互斥锁
import threading# 全局变量
g_num = 0# 对g_num进行加操作
def sum_num1():for i in range(1000000):# 声明全局变量global g_numg_num += 1print("g_num1:",g_num)# 对g_num进行加操作
def sum_num2():for i in range(1000000):# 声明全局变量global g_numg_num += 1print("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()

2.8 互斥锁的使用

1.互斥锁的使用

threading.Lock()

2.上锁

mutex.acquire()

3.解锁

mutex.release()

import threading# 全局变量
g_num = 0# 对g_num进行加操作
def sum_num1():# 上锁mutex.acquire()for i in range(1000000):# 声明全局变量global g_numg_num += 1# 解锁mutex.release()print("g_num1:",g_num)# 对g_num进行加操作
def sum_num2():# 上锁mutex.acquire()for i in range(1000000):# 声明全局变量global g_numg_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()

 

2.9 死锁

死锁:一直等待对方释放锁的情景就是死锁。

死锁的结果:会造成应用程序停止响应,不能再处理其它任务了。

死锁的注意点:

  • 使用互斥锁的时候需要注意死锁的问题,在合适的地方注意释放锁。
  • 死锁一旦产生就会造成应用程序的停止响应,应用程序无法继续往下执行了。
import threading# 全局变量
g_num = 0# 对g_num进行加操作
def sum_num1():print("sum_num1...")# 上锁mutex.acquire()for i in range(1000000):# 声明全局变量global g_numg_num += 1print("g_num1:",g_num)# 对g_num进行加操作
def sum_num2():print("sum_num2...")# 上锁mutex.acquire()for i in range(1000000):# 声明全局变量global g_numg_num += 1print("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()

线程sum1_thread占用锁资源,而线程sum2_thread请求锁资源,导致死锁,线程无法继续运行下去。

2.10 进程和线程的对比

2.10.1 关系对比

线程是依附在进程里面的,没有进程就没有线程。

一个进程默认提供一条线程,当然进程可以创建多个线程。

2.10.2 区别对比

进程之间不共享全局变量,而线程之间共享全局变量(但是要注意资源竞争的问题)。

创建进程的资源开销大于线程。

进程是OS资源分配的基本单位,线程是CPU调度的基本单位。

线程不能独立执行,必须依存在进程中。

2.10.3 优缺点

1.进程优缺点:

优点:可以用多核(多个进程并行执行)。

缺点:资源开销大。

2.线程优缺点:

优点:资源开销小。

缺点:只能使用单核(多个线程并发执行)。

相关内容

热门资讯

猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...