当前位置: 首页 > news >正文

python并发编程

多任务

在同一时间内执行多个任务

表现形式

  • 并发:在一段时间内,交替执行任务
  • 并行:在一段时间内,真正的同时一起执行多个任务

并发和并行的区别

  • 并发:多个任务同时请求执行,但是在同一瞬间,CPU只能执行一个任务,于是安排它们交替执行,看起来好像是同时执行的,其实并不是,CPU在作者高效的切换
  • 并行:多个人同时执行,前提是需要多核CPU

多任务的优势

能够充分利用CPU资源,提高程序执行效率

进程

进程是CPU资源分配的最小单位,它是操作系统进行资源分配和调度运行的基本单位

通俗理解:一个正在运行的程序就是一个进程

多进程的作用

使用多进程可以打打提高程序的执行效率

python中多进程的基本工作方式

程序运行起来形成主进程,在主进程上创建子进程

多进程的代码实现

  1. 引入进程工具包
  2. 通过进程类实例化进程对象
  3. 启动进程执行任务
import multiprocessing子进程对象 = multiprocessing.Process()
子进程对象.start()

参数详解

multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={})
  • group:参数未使用,值始终为None
  • target: 表示调用对象,即子进程要执行的任务(回调函数入口地址)
  • args: 表示以元组的形式向子任务函数传参,元组方式传参一定要和参数的顺序保持一致
  • kwargs:表示以字典的方式给子任务函数传参,字典方式传参字典中的key要和参数名保持一致
  • name: 子进程的名称

无参数模拟

# 使用多进程模拟一遍写代码,一遍听音乐import multiprocessing
import timedef coding():for i in range(3):print("正在写代码...")time.sleep(0.2)def music():for i in range(3):print("正在听音乐...")time.sleep(0.2)if __name__ == "__main__":# 创建进程对象coding_process = multiprocessing.Process(target=coding)music_process = multiprocessing.Process(target=music)# 启动进程coding_process.start()music_process.start()

带参数模拟

import multiprocessing
import timedef coding(name,num):for i in range(num):print(f"{name}正在写第{i}行代码...")time.sleep(0.1)def music(name,count):for i in range(count):print(f"{name}正在听第{i}首音乐...")time.sleep(0.1)if __name__ == "__main__":# 创建进程对象coding_process = multiprocessing.Process(target=coding,name='刘亦菲',args=("小明",10))music_process = multiprocessing.Process(target=music,name='胡歌',kwargs={"name":"小红","count":20})print(f"coding_process进程的名字是:{coding_process.name}")print(f"music_process进程的名字是:{music_process.name}")# 启动进程# 启动进程coding_process.start()music_process.start()

获取进程编号

进程编号的作用

进程编号唯一标识一个进程,方便管理进程。在一个操作系统中,一个进程拥有的进程号是唯一的,进程号可以反复使用。获取进程编号的目的是验证主进程和子进程的关系,可以得知子进程是由那个主进程创建出来的

获取当前进程的编号

  • os.getpid()
import os
# 获取当前进程的PID
pid = os.getpid()
print(pid)
  • multiprocessing.current_process().pid
import multiprocessing
pid = multiprocessing.current_process().pid
print(pid)

获取父进程编号

import os
ppid = os.getppid()
print(ppid)

综合案例

import os
import multiprocessingprint(f"当前进程的pid是:{os.getpid()},{multiprocessing.current_process().pid},它的父进程id是:{os.getppid()}")

进程的注意介绍

  1. 进程之间不共享全局变量
  2. 主进程会等待所有的子进程执行结束后再结束

例:在不同进程中修改里表s_list[] 并新增元素,试着在各个进程中观察列表的最终结果

import multiprocessing
import times_list = []def write_data():for i in range(3):s_list.append(i)print(f"add:{i}")print(f"write_data:{s_list}")def read_data():print(f"read_data:{s_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()   """
add:0
add:1
add:2
write_data:[0, 1, 2]
read_data:[]
"""

执行结果细节:

  1. 进程之间数据是相互隔离的,不能共享
  2. 子进程相当于父进程的副本,即 把父进程的内容拷贝一遍,单独执行

主进程-子进程同步结束

默认情况下,主进程会等待所有子进程执行结束后再结束,如果不让主进程等待子进程,方法如下

  • 子进程设置守护进程
import multiprocessing
import timedef work():for i in range(10):print("工作中...")time.sleep(0.2)if __name__ == "__main__":# 创建子进程sub_process = multiprocessing.Process(target=work)# 设置守护主进程,主进程退出子进程直接销毁,不再执行子进程中的代码sub_process.daemon = Truesub_process.start()time.sleep(1)print("主进程执行结束")
  • 子进程自己主动终止
import multiprocessing
import timedef work():for i in range(10):print("工作中...")time.sleep(0.2)if __name__ == "__main__":# 创建子进程sub_process = multiprocessing.Process(target=work)sub_process.start()time.sleep(1)sub_process.terminate()  # 终止子进程,不建议使用,僵尸进程,不会清理资源print("主进程执行结束")

线程

线程的概念

进程是分配资源的基本 单位,一旦创建一个进程就会分配一定的资源;现成是CPU调度的基本单位,每个进程至少都有一个线程,而这个线程就是我们通常说的主线程。

线程的创建步骤

# 1. 导入线程模块
import threading
# 2. 通过线程类创建线程对象
线程对象 = threading.Thread(target=任务名)
# 启动线程执行任务
线程对象.start()

参数详解

线程对象=threading.Thread([group[,target[,name[,args[,kwargs]]]]])
  • group: 线程组。目前只能使用None
  • target 执行的目标任务名
  • args: 以元组的方式给执行任务传参,元组方式传参一定要和目标任务函数参数顺序保持一致
  • kwargs: 以字典方式给执行任务传参,字典方式传参字典中的key一定要和参数的顺序保持一致
  • name: 线程名,一般不用设置

线程不带参数任务

例:使用线程模拟一边写代码,一边听音乐功能

import threading
import timedef coding():for i in range(3):print("正在写代码...")time.sleep(0.2)def music():for i in range(3):print("正在听音乐...")time.sleep(0.2)if __name__ == "__main__":# 创建子线程sub_thread1 = threading.Thread(target=coding)sub_thread2 = threading.Thread(target=music)# 启动子线程sub_thread1.start()sub_thread2.start() 

线程带参数的任务

例:使用线程模拟一边编写num行代码,一边听count收音乐的功能

import threading
import timedef coding(num,name):for i in range(num):print(f"{name}正在写第{i}行代码...")time.sleep(0.2)def music(count,name):for i in range(count):print(f"{name}正在听第{i}首音乐...")time.sleep(0.2)if __name__ == "__main__":# 创建子线程sub_thread1 = threading.Thread(target=coding,args=(5,"zhangsan"))sub_thread2 = threading.Thread(target=music,kwargs={"count":5,"name":"lisi"})# 启动子线程sub_thread1.start()sub_thread2.start() 

线程的注意介绍

  1. 线程之间执行时无序的
  2. 主线程会等待所有的子线程执行结束后再结束
  3. 线程之间共享全局变量
  4. 多个线程操作全局变量数据时要注意线程安全问题

守护线程

设置守护线程有两种方式

  • 创建线程时
线程对象 = threading.Thread(target=任务名,daemon=True)
  • 调用线程对象方法
线程对象.setDaemon(True)

线程安全

互斥锁

对共享数据进行锁定,保证同一时刻只有一个线程去操作

互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到锁的线程进行等待,等锁使用完释放后,其他等待的线程再去抢这个锁

互斥锁的使用流程
# 1. 互斥锁的创建
lock= threading.Lock()
# 2. 上锁
lock.acquire()
# 3. 释放锁
lock.release()

例:定义两个函数,实现循环100万次,每循环一次给全局变量加1,创建两个子线程执行对应的两个函数,添加互斥锁后,查看计算后的记过

import threading
# 定义全局变量
g_num = 0
# 创建互斥锁
lock = threading.Lock()def sum_num1():# 声明全局变量global g_numlock.acquire()  # 上锁for i in range(1000000):g_num += 1lock.release()  # 解锁print("sum1:", g_num)def sum_num2():# 声明全局变量global g_numlock.acquire()  # 上锁for i in range(1000000):g_num += 1lock.release()  # 解锁print("sum2:", g_num)if __name__ == "__main__":# 创建两个子线程first_thread = threading.Thread(target=sum_num1)second_thread = threading.Thread(target=sum_num2)# 启动线程first_thread.start()second_thread.start()

相关文章:

  • 【力扣】2434.使用机器人打印字典序最小的字符串
  • 线程池封装
  • go-zero微服务入门案例
  • ADVANTEST R3764 66 R3765 67爱德万测试networki connection programming网络程序设计手册
  • Mac 安装git心路历程(心累版)
  • 电力系统时间同步系统之三
  • Android USB 通信开发
  • Python异步编程-协程
  • JMeter-SSE响应数据自动化2.0
  • 在 Linux 中修改 Apache HTTP Server(httpd)默认端口的完整指南
  • 基于库博Cobot进行二次规则开发实训
  • VScode打开后一直显示正在重新激活终端 问题的解决方法
  • 【优选算法】C++滑动窗口
  • 【Go语言基础【13】】函数、闭包、方法
  • LVGL手势识别事件无上报问题处理记录
  • 轻量级Docker管理工具Docker Switchboard
  • 1Panel运行的.net程序无法读取系统字体(因为使用了docker)
  • Docker基础(一)
  • 使用 Python + SQLAlchemy 创建知识库数据库(SQLite)—— 构建本地知识库系统的基础《一》
  • 牛客练习赛140
  • 外管局网站做延期收汇报告/百度推广代理
  • 做旅游的网站的要素/最简单的网页制作
  • 做网站在阿里云上面买哪个服务/快速排名优化
  • 全球网站排名查询/谈谈你对互联网营销的认识
  • 网站系统下载不了文件/seo还有前景吗
  • 茶叶网站建设策划书/大连网站优化