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

Python---多进程---多线程

总结

1- 多进程:计算机分配资源的最小单位。
2- 多线程:CPU进行任务切换的最小单位。
3- 线程不能独立存在,必须存在在进程中。
4- 多进程中,多个子进程和主进程间,不会共享全局变量
5- 多线程中,多个子线程和主线程间,会共享全局变量
6- 将子线程,标记为守护线程。只有设置为守护线程的,才会在主线程运行结束后,跟着结束。否则不受任何影响

  • 并发与并行
    • 并发:在一段时间内快速交替去执行多个任务(多线程)
    • 并行:在一段时间内真正的同时一起执行多个任务(多进程)
  • 进程(Process)
    • 是操作系统进行资源分配的基本单位
    • 进程可以有一个或多个子进程
    • 最原始的父进程是由操作系统提供的
  • 线程(Thread)
    • 是CPU进行调度的基本单位
    • 线程可以有一个或多个子线程
    • 线程是由进程主动创建出来的,创建第一次创建子线程时才会出现主线程
  • 线程的资源共享问题(只存在于低版本的Python解释器比如3.6.5,3.10已解决):当多个线程同时操作同一个共享的全局变量时,可能会造成错误的结果,解决办法如下
    • 线程同步:保证同一时刻只能有一个线程去操作共享资源(全局变量)
      • 线程等待thread.join()
        • 让一个线程完全执行结束,再去执行另一个线程
        • 缺点:一个执行完再执行另一个,和单任务几乎没有区别
      • 互斥锁:
        • 多个线程去抢同一把"锁",threading.Lock()抢到锁的线程执行,没抢到锁的线程会阻塞等待。
        • 缺点:虽然保障程序执行的多任务,如果频繁的加锁、释放锁会额外增加执行的时间消耗
    • 从场景下手:不用多线程做累加count操作,只做append操作!
  • 进程线程对比
    • 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位。
    • 线程不能够独立执行,必须依存在进程中。
    • 创建进程的资源开销要比创建线程的资源开销要大。
    • 进程之间不共享全局变量,线程之间共享全局变量,但是在低版本的Python中要注意线程资源竞争的问题。
    • 进程稳定性高,适合计算密集型任务;线程适合IO密集型任务
    • 目前Python多线程不能利用CPU多核心优势,想利用CPU多核心的优势,Python只能采用多进程

多进程

多进程实例

import time
import os
import multiprocessing
# os.getpid():process id,获取进程的编号
# os.getppid():parent process id,获取父进程编号# 跳舞函数
def dance():print(f'dance进程的编号:{os.getpid()},父进程编号:{os.getppid()}')for i in range(5):print('跳舞中...')# 休眠1秒钟time.sleep(1)# 唱歌函数
def sing():print(f'sing进程的编号:{os.getpid()},父进程编号:{os.getppid()}')for i in range(5):print('唱歌中...')# 休眠1秒钟time.sleep(1)if __name__ == '__main__':# 最原始的父进程是由操作系统提供的print(f'主进程的编号为:{os.getpid()},父进程编号:{os.getppid()}')# 创建两个进程,一个执行 dance 函数,另一个执行 sing 函数dance_process = multiprocessing.Process(target=dance)sing_process = multiprocessing.Process(target=sing)# 启动进程dance_process.start()sing_process.start()

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

import multiprocessing
import time# 带有参数的任务(函数)
def task(count):for i in range(count):print('任务执行中...')time.sleep(0.2)else:print('任务执行完成')if __name__ == '__main__':# 传参方式1 args=(参数值1, ...)# task_process = multiprocessing.Process(target=task, args=(3,))# 传参方式2 kwargs={'形参字符串1': 值1, '形参字符串2': 值2, ...}task_process = multiprocessing.Process(target=task, kwargs={'count': 5})# 启动进程task_process.start()task_process.join()print('这行代码一定等task_process进程执行完毕之后才会运行,打印')

多进程之间不共享变量

import multiprocessing
import time# 定义全局变量
g_list = []# 添加数据的函数
def add_data():for i in range(5):g_list.append(i)print('add:', i)time.sleep(0.2)print('add:', g_list)# 读取数据的函数
def read_data():print('read:', g_list)if __name__ == '__main__':# 创建添加数据的子进程add_data_process = multiprocessing.Process(target=add_data)# 创建读取数据的子进程read_data_process = multiprocessing.Process(target=read_data)# 启动添加数据子进程add_data_process.start()# 阻塞等待:主进程等待 add_data_process 执行完成,再向下继续执行add_data_process.join()# 启动读取数据子进程read_data_process.start()# 主进程读取数据print('main:', g_list)# 主进程延时 1stime.sleep(1)print('主进程结束!')

子进程设置为守护进程

主进程结束,设为守护进程的子进程主动GG

import multiprocessing
import timedef task():for i in range(10):print('任务执行中...')time.sleep(0.5)if __name__ == '__main__':# 创建子进程并启动sub_process = multiprocessing.Process(target=task)# TODO:设置子进程为守护进程sub_process.daemon = Truesub_process.start()# 主进程延时 1stime.sleep(1)print('主进程结束!')

主进程终止子进程

子进程被动GG

import multiprocessing
import time# 任务函数
def task():for i in range(10):print('任务执行中...')time.sleep(0.5)if __name__ == '__main__':# 创建子进程并启动sub_process = multiprocessing.Process(target=task)sub_process.start()# 主进程延时 1stime.sleep(1)print('主进程结束!')# TODO: 终止子进程sub_process.terminate()

多线程

多线程实例

import time
import threading# 跳舞函数
def dance(num):for i in range(num):print('跳舞中...')time.sleep(1)# 唱歌函数
def sing(num):for i in range(num):print('唱歌中...')time.sleep(1)if __name__ == '__main__':# 创建两个线程,分别执行 dance 和 singdance_thread = threading.Thread(target=dance, args=(5,))sing_thread = threading.Thread(target=sing, kwargs={'num':5})# 启动线程dance_thread.start()sing_thread.start()

线程共用全局变量

import threading
import time# 定义全局变量
g_list = []# 添加数据的函数
def add_data():for i in range(5):g_list.append(i)print('add:', i)time.sleep(0.2)print('add:', g_list)# 读取数据的函数
def read_data():print('read:', g_list)if __name__ == '__main__':# 创建添加数据的子线程add_data_thread = threading.Thread(target=add_data)# 创建读取数据的子线程read_data_thread = threading.Thread(target=read_data)# 启动添加数据子线程add_data_thread.start()# 阻塞等待:主线程等待 add_data_thread 执行完成,再向下继续执行add_data_thread.join()# 启动读取数据子线程read_data_thread.start()# 阻塞等待:主线程等待 read_data_thread 执行完成,再向下继续执行read_data_thread.join()print('main:', g_list)

join()使用总结:
1- 作用:线程等待子线程执行结束
2- 使用场景:主线程需要使用多个子线程运行的最终结果,才能够继续往下运行。
举例:吃火锅,张三叫李四带点食材,并且张三叫王五带锅。有了锅和食材以后,才能够开始煮火锅

线程互斥锁

注释lock锁相关代码,并使用 低版本的Python解释器(python3.6.5) 才能看到线程资源安全问题的效果!Python 3.10 已经解决了该问题!

# 互斥锁:多个线程去抢同一把"锁",抢到锁的线程执行,没抢到锁的线程会阻塞等待
import threading# 定义全局变量
g_num = 0# 创建一个多线程互斥锁
lock = threading.Lock()def sum_num1():global g_num# 循环一次给全局变量加1for i in range(1000000):# 抢到锁,代码可以继续向下执行,否则就会阻塞等待lock.acquire() # 抢锁g_num += 1lock.release() # 释放锁print('sum1:', g_num)def sum_num2():global g_num# 循环一次给全局变量加1for i in range(1000000):# 抢到锁,代码可以继续向下执行,否则就会阻塞等待lock.acquire() # 抢锁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()# 阻塞等待:主线程等待子线程结束再向下运行first_thread.join()second_thread.join()print(g_num)

相关文章:

  • <JavaEE> TCP 的通信机制(四) -- 流量控制 和 拥塞控制
  • Python 中的运算符介绍(1)
  • 第二节 linux操作系统安装与配置
  • 进阶学习——Linux系统磁盘管理与文件系统
  • 4、内存泄漏检测(多线程)
  • 【网络安全 | Misc】miss_01 太湖杯
  • OSPF的DR与BDR-新版(16)
  • MariaDB单机多实例的配置方法
  • Vue - 使用Element UI Upload / importExcelJs进行文件导入
  • 【C语言学习疑难杂症】第12期:如何从汇编角度深入理解y = (*--p)++这行代码(易懂版)
  • php的laravel权限问题
  • 【开源】基于Vue+SpringBoot的二手车交易系统
  • MySQL一些常用命令
  • Unity UnityWebRequest 在Mac上使用报CommectionError
  • 不给病毒留空子:保护您的数据免受.mallox勒索病毒威胁
  • 【mysql】环境安装、服务启动、密码设置
  • AWS实战 - 利用IAM对S3做访问控制
  • Django 博客开发教程 16 - 统计文章阅读量
  • Github访问慢解决办法
  • iOS | NSProxy
  • JAVA SE 6 GC调优笔记
  • Java程序员幽默爆笑锦集
  • JS笔记四:作用域、变量(函数)提升
  • Koa2 之文件上传下载
  • npx命令介绍
  • Sublime Text 2/3 绑定Eclipse快捷键
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • 成为一名优秀的Developer的书单
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 面试遇到的一些题
  • 前端性能优化--懒加载和预加载
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 2017年360最后一道编程题
  • 进程与线程(三)——进程/线程间通信
  • ()、[]、{}、(())、[[]]命令替换
  • (7)STL算法之交换赋值
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (七)c52学习之旅-中断
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)创业的注意事项
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • .form文件_一篇文章学会文件上传
  • .gitignore文件_Git:.gitignore
  • .Net - 类的介绍
  • .NET CF命令行调试器MDbg入门(三) 进程控制
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET委托:一个关于C#的睡前故事
  • [ 隧道技术 ] cpolar 工具详解之将内网端口映射到公网
  • [ACTF2020 新生赛]Upload 1
  • [AIGC] Redis基础命令集详细介绍