网络通信与并发编程(六)线程、进程池与线程池

线程、进程池与线程池

文章目录

  • 线程、进程池与线程池
  • 一、线程
  • 二、线程的相关操作
    • 2.1创建线程的两种方式
    • 2.2线程的其他操作
    • 2.3死锁现象和递归锁
    • 2.4条件
    • 2.5定时器
    • 2.6 队列与堆栈
  • 三、进程池与线程池

一、线程

线程是指cpu上实际执行计算的单位,而进程是将计算所需资源的一个集合(内存分配释放,资源的申请销毁等等)。举个例子,进程好比是车间,而线程则是车间的流水线,流水线是实际的生产工具,而车间是集合生产资源的地方。

线程的特点以及进程线程的区别:

  • 当一个进程被创建以后,默认会带着一个线程,称之为主线程
  • 一个进程中可以创建多条线程,各个线程间共享资源;而父进程创建子进程以后,子进程会获得父进程的数据副本,但是父进程与子进程间数据是隔离开的
  • 线程创建切换的速度快,创建消耗小,而进程创建切换的速度慢,创建消耗大
  • cpu的并发本质是在多个线程之间进行切换
  • 多进程之间使用不同的地址空间,而一个进程中的线程共用进程的地址空间

何时使用多进程?何时使用多线程?
(cpu多核情况下)若执行的任务是cup密集型的(大量计算任务),则使用多进程。因为python中的多线程无法使用多核cpu的优势,为了充分发挥多核cpu的计算力则需要使用多进程。
若执行任务是I/O密集型的(如网络通信等等),则使用多线程。I/O密集型任务涉及大量的I/O操作,而多个进程间的来回切换对比于多个线程之间而言消耗更多时间与资源。

多线程工作的具体例子:你打开一个文字处理软件,该软件需要监听键盘输入、处理文字信息、将内容保存至硬盘。这三件事情都涉及操作内存中的同一块数据,显然使用多进程并不合适,所以使用多线程的方式,开启三个线程同时处理三个任务,相互配合完成文字处理软件的功能。

二、线程的相关操作

2.1创建线程的两种方式

开启线程的方式与进程相似,这里就不详细介绍了。

#方式一
#currentThread方法可以查看当前运行线程的相关信息
from threading import Thread,currentThread
import timedef task():print('%s is running' %currentThread().name)time.sleep(3)print('%s is done' %currentThread().name)#由于线程间共享主进程的资源,创建子线程不会导入主线程的代码,所以下方代码可以不写
#if __name__ == '__main__':
t=Thread(target=task,name='子线程')
t.start()
print('主')
#方式二
from threading import Thread
import timeclass Mythread(Thread):def run(self):print('%s is running' %self.name)time.sleep(3)print('%s is done' %self.name)#if __name__ == '__main__':
t=Mythread(name='子线程')
t.start()
print('主')

同样的主进程(主线程)需要等其所有的子线程运行结束以后才会结束。

2.2线程的其他操作

由于多个线程共享主进程的内存空间,所以多个线程的pid号和主进程是相同的

from threading import Thread
import osclass Mythread(Thread):def run(self):print('%s的pid:%s' %(self.name,os.getpid()))for i in range(5):t=Mythread(name='子线程%d'%i)t.start()
print('主进程的pid:%s'%os.getpid())

运行结果:
在这里插入图片描述

线程中的join、is_alive、name属性方法的使用和进程相同,这边不在介绍了。

threading.currentThread()该方法可以查看当前线程的相关信息
threading.enumerate()该方法可以返回一个包含正在运行线程的列表
threading.activeCount()该方法可以返回正在运行线程的数量

守护线程的创建方式和守护进程相同,但是守护线程需要主进程内的所有子线程都运行完以后才会结束,而守护进程则是主进程的代码运行结束就会结束了。
补充一句:上面说的守护进程/线程的结束是指主进程代码结束/主进程线程结束时守护进程/线程还没运行结束会被强制结束。

from threading import Thread
import time
def foo():print(123)time.sleep(2)print("end123")def bar():print(456)time.sleep(3)print("end456")t1=Thread(target=foo)
t2=Thread(target=bar)t1.daemon=True
t1.start()
t2.start()
print('主进程运行结束')

运行结果:
123
456
主进程运行结束
end123
end456

线程的互斥锁使用方式与进程相同

from threading import Thread,Lock
import timemutex=Lock()x=100
def task():global xmutex.acquire()temp=xtime.sleep(0.1)x=temp-1mutex.release()if __name__ == '__main__':t_l=[]for i in range(100):t=Thread(target=task)t_l.append(t)t.start()for t in t_l:t.join()stop=time.time()print(x)

2.3死锁现象和递归锁

进程与线程都有死锁现象(进程中忘了介绍,在这补充),死锁现象是指两个或以上的进程/线程争抢资源时出现相互等待的情况。举个通俗点的例子就是甲乙两人一人在厨房,一人在厕所,甲现在想上厕所需要等乙出来,而乙现在想去厨房又需要等甲出来。两人相互等待对方停滞在原地的行为就是死锁现象。

from threading import Thread,Lock
import timemutexA=Lock()
mutexB=Lock()class Mythread1(Thread):def run(self):self.f1()def f1(self):mutexA.acquire()print('%s 锁上厕所' %self.name)time.sleep(1)mutexB.acquire()print('%s 锁上厨房' %self.name)mutexA.release()print('%s 开锁厕所' % self.name)mutexB.release()print('%s 开锁厨房' % self.name)class Mythread2(Thread):def run(self):self.f2()def f2(self):mutexB.acquire()print('%s 锁上厨房' % self.name)time.sleep(1)mutexA.acquire()print('%s 锁上厨房' % self.name)mutexB.release()print('%s 开锁厕所' % self.name)mutexA.release()print('%s 开锁厨房' % self.name)t1=Mythread1(name='线程1')
t2=Mythread2(name='线程2')
t1.start()
t2.start()

上述代码中线程1拿到A锁后等待1s,期间线程2拿到B锁,线程1与线程2相互等待对方释放锁从而停滞在了原地。为了解决这个问题可以将锁改为递归锁。
递归锁和互斥锁的区别在于互斥锁的使用者每次只能申请上锁一次,而递归锁的使用者可以多次申请上锁。互斥锁和递归锁同样要求只有使用者上的所有锁释放以后其他使用者才能使用。

from threading import Thread,RLock
import time#递归锁相当于一把锁可以锁多个资源
mutexA=RLock()class Mythread1(Thread):def run(self):self.f1()def f1(self):mutexA.acquire()print('%s 锁上厕所' %self.name)time.sleep(1)mutexA.acquire()print('%s 锁上厨房' %self.name)mutexA.release()print('%s 开锁厕所' % self.name)mutexA.release()print('%s 开锁厨房' % self.name)class Mythread2(Thread):def run(self):self.f2()def f2(self):mutexA.acquire()print('%s 锁上厨房' % self.name)time.sleep(1)mutexA.acquire()print('%s 锁上厨房' % self.name)mutexA.release()print('%s 开锁厕所' % self.name)mutexA.release()print('%s 开锁厨房' % self.name)t1=Mythread1(name='线程1')
t2=Mythread2(name='线程2')
t1.start()
t2.start()

运行结果:
线程1 锁上厕所
线程1 锁上厨房
线程1 开锁厕所
线程1 开锁厨房
线程2 锁上厨房
线程2 锁上厨房
线程2 开锁厕所
线程2 开锁厨房

线程的信号量和事件使用方法和进程相同,这里不在介绍了,只要注意导入方式需从multiprocessing变为threading

2.4条件

条件:使用线程只有满足某个条件时才能被释放。

from threading import Thread,Conditiondef user_input():while True:if input("输入1退出")=='1':return Truedef work():con.acquire()con.wait_for(user_input)con.release()con=Condition()
t=Thread(target=work)
t.start()
from threading import Thread,Condition
import timedef work():con.acquire()print(11111111111111111111111111111111)con.wait()con.release()con=Condition()
t=Thread(target=work)
t.start()
con.acquire()
time.sleep(3)
#该函数配合con.wait()使用,可以随机唤醒一个等待中的线程
con.notify()
con.release()

2.5定时器

#1s后打印hello
from threading import Timerdef p():print('hello')t=Timer(1,p)
t.start()

2.6 队列与堆栈

queue中一些方法的具体使用方式和进程中介绍的Queue一样,这里就不再介绍了。

import queue
q=queue.Queue(2)
#入队列
q.put(1)
#出队列
q.get()#含有优先级的队列
qq=queue.PriorityQueue(2)
#元组第一个是优先级,数字越小优先级越高(也可以是字母的比较)
qq.put((30,50))
qq.put((10,40))
print(qq.get())
print(qq.get())#堆栈
qqq=queue.LifeQueue(2)
q.put(1)
q.get()

三、进程池与线程池

池的功能是限制启动的进程数或线程数。当并发的任务数远远超过了计算机的承受能力时,即无法一次性开启过多的进程数或线程数时,就应该用池将开启的进程数或线程数限制在计算机可承受的范围内。

#使用Pool的同步调用的进程池
from multiprocessing import Pool
import os,time
def work(n):print('%s run' %os.getpid())time.sleep(3)return n**2if __name__ == '__main__':p=Pool(3)res_l=[]for i in range(4):#apply为同步调用(一个进程执行完后才执行下一个进程),res为进程的返回值res=p.apply(work,args=(i,))res_l.append(res)print(res_l)
#使用Pool的异步调用的进程池
from multiprocessing import Pool
import os,time
def work(n):print('%s run' %os.getpid())time.sleep(3)return n**2def parse(res):time.sleep(1)print('返回值:%s'%(res**2))if __name__ == '__main__':p=Pool(3)for i in range(4):#apply_async为异步调用,主进程提交申请后会继续执行下方的代码#当子进程运行结束后主进程才会调用回调函数处理子进程的返回值#res返回的是子进程的对象res=p.apply_async(work,args=(i,),callback=parse)#下面两行功能是等待子进程运行结束p.close()p.join()
#concurrent.futures模块提供了高度封装的异步调用的进程池/线程池
#ProcessPoolExecutor/ThreadPoolExecutor表示进程池/线程池
#若想使用同步调用的进程池可以使用multiprocessing.Pool模块
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
from multiprocessing import current_process
import timedef task(n):print('%s run...' %current_process().name)time.sleep(5)#进程池只支持返回picklable的对象return n**2def parse(future):time.sleep(1)#获取返回值res=future.result()print('%s 处理了 %s' %(current_process().name,res))if __name__ == '__main__':# 开启进程池,限制启动进程数为4(默认为cpu核数,而线程池限制数默认为cpu核数*5)pool=ProcessPoolExecutor(4)for i in range(1,5):#向进程池提交进程(开启进程)future=pool.submit(task,i)#回调函数,当子进程运行结束后会执行回调函数处理子进程的返回值#进程池中是主进程执行回调函数,线程池中是空闲的子线程执行回调函数future.add_done_callback(parse)#关闭进程池(无法在向池中提交进程)#如果wait=True则主进程阻塞等待子进程运行结束后在执行下方代码,反则则会立即结束所有子进程pool.shutdown(wait=True)print('主',current_process().name)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/457299.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

潮畔汽车文化营地开营啦!全民测试场启动典礼圆满成功

在这个充满活力与创新的时代,汽车已不仅仅是代步工具,它承载着人们对速度、自由、科技与梦想的追求,成为了一种生活方式的象征。随着汽车文化的日益丰富和多元化,如何更好地连接汽车制造商、消费者以及广大汽车爱好者,…

群控系统服务端开发模式-应用开发-业务架构逻辑开发准备工作

安装与仓库已经调整完毕,现在开发业务架构逻辑,其次再开发功能逻辑。业务架构逻辑开发与功能逻辑开发不是一回事,一定要明白。业务架构指的是做某一件事或是某一种类型的事的逻辑,在互联网web应用中通常指一套系统的外在逻辑&…

Vue学习笔记(四)

事件处理 我们可以使用 v-on 指令 (通常缩写为 符号) 来监听 DOM 事件,并在触发事件时执行一些 JavaScript。用法为 v-on:click"methodName" 或使用快捷方式 click"methodName" 事件处理器的值可以是: 内联事件处理器&#xff1…

Jetpack架构组件_LiveData组件

1.LiveData初识 LiveData:ViewModel管理要展示的数据(VM层类似于原MVP中的P层),处理业务逻辑,比如调用服务器的登陆接口业务。通过LiveData观察者模式,只要数据的值发生了改变,就会自动通知VIEW层&#xf…

基于Python大数据的王者荣耀战队数据分析及可视化系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…

IDEA开发工具使用技巧积累

一、IDEA 工具设置默认使用maven的settings.xml文件 第一步:打开idea工具,选中 File ——> New Projects Setup ——> Settings for New Projects 第二步:先设置下自动构建项目这个选项 第三步:选中 Build Tools ——>…

windows下pycharm社区版2024下载与安装(包含新建第一个工程)

windows下pycharm社区版2024下载与安装 下载pycharm pycharm官网 安装pycharm 1.进入官网 pycharm官网 下载 点击Download–>右侧Other versions 下载对应的社区版(如下图):下载网址 2.点击运行下载好的安装包 点击下一步 3.更改pychar…

2020款Macbook Pro A2251无法充电无法开机定位及修复

问题背景 up主有一台2020年的Macbook Pro,带Touch Bar,16G512G,四核I5,型号A2251 应该是一周没充电了,之前还用的好好的,后来有一天出差想带上 打开没电,手头上有个小米的66W快充头&#xff0c…

C#的自定义Tip窗体 - 开源研究系列文章

上次编写了自定义的提示和对话框窗体,这次记录的是自定义的Tip窗体,用于显示提示操作。有时间没编程了,这次就当进行了记录。 1、 项目目录; 2、 源码介绍; 1) 实现; 2) 应用; 3、 运行界面&…

Leetcode刷题笔记12

HJ1 字符串最后一个单词的长度 字符串最后一个单词的长度_牛客题霸_牛客网 这里可以使用rfind(),rfind()函数从字符串的末尾向前查找第一个空格的位置。这个空格将是最后一个单词和前面的单词的分隔符。首先使用getline读取字符串,然后用rfind找到最后一…

现在设备普遍切换成TYPE-C适配器后,一拖三数据线接口变革探析

随着科技的飞速发展,电子设备的接口标准也在不断地更新换代。近年来,TYPE-C接口凭借其高速传输、正反可插等显著优势,逐渐成为了众多电子设备的主流接口。从智能手机到平板电脑,从笔记本电脑到移动电源,TYPE-C接口的应…

Java-图书管理系统

我的个人主页 欢迎来到我的Java图书管理系统,接下来让我们一同探索如何书写图书管理系统吧! 1管理端和用户端 2建立相关的三个包(book、operation、user) 3建立程序入口Main类 4程序运行 1.首先图书馆管理系统分为管理员端和…

TPLCM柔性屏自动化贴合应用

在当前的显示屏制造领域,TP&LCM贴合技术是推动产品升级和满足市场需求的关键环节。随着技术的不断进步,全贴合技术因其卓越的显示效果和用户体验,逐渐成为中高端产品的标配。然而,这一技术的高精度要求和复杂工艺也带来了诸多…

物联网数据采集网关详细介绍-天拓四方

一、物联网数据采集网关的概述 物联网数据采集网关,简称数据采集网关,是物联网系统中的重要组成部分,位于物联网设备和云端平台之间。其主要职责是实现数据的采集、汇聚、转换、传输等功能,确保来自不同物联网设备的数据能够统一…

学习笔记——动态路由——OSPF(距离矢量协议)OSPF路由类型

OSPF路由类型 在OSPF中,路由类型指的是不同种类的路由,用于描述网络中不同的路由信息及其传输方式。 1、Intra Area路由(区域内路由) Intra Area路由(区域内路由/本地路由/内部路由)是OSPF协议中的一种路由类型,用于描述在同一个OSPF区域内…

小白直接冲!一区蛇群优化算法+双向深度学习+注意力机制!SO-BiTCN-BiGRU-Attention多输入单输出回归预测

小白直接冲!一区蛇群优化算法双向深度学习注意力机制!SO-BiTCN-BiGRU-Attention多输入单输出回归预测 目录 小白直接冲!一区蛇群优化算法双向深度学习注意力机制!SO-BiTCN-BiGRU-Attention多输入单输出回归预测预测效果基本介绍程…

Linux相关概念和易错知识点(16)(Shell原理、进程属性和环境变量表的联系)

Shell原理及其模拟实现 在认识进程exec系列函数、命令行参数列表、环境变量之后,我们可以尝试理解一下Shell的原理,将各方知识串联起来,让Shell跑起来才能真正理解这些概念。我会以模拟Shell执行的原理模拟一个Shell。途中配上相关讲解。 1…

Mybatis-03.入门-配置SQL提示

一.配置SQL提示 目前的Springboot框架在mybatis程序中编写sql语句并没有给到任何的提示信息,这对于开发者而言是很不友好的。因此我们需要配置SQL提示。 配置SQL提示 这样再去写SQL语句就会有提示了。 但是会发现指定表名时并没有给出提示。这是因为&#xff1a…

用kali入侵 DarkHole_2测试

进入kali系统调出root交互式界面 netdiscover -r 000.000.000.000/24 -------局域网探测IP工具 nmap 设备端口扫描 发现两个攻击点一个是80端口的Http 一个是22端口的ssh 发现有许多GIT文件 可能会出现git源码泄露 使用githack URL 命令还原git源文件 打开面板控制命令行 输入…

2024数学分析【南昌大学】

计算极限 lim ⁡ n → ∞ 2024 n ( 1 − cos ⁡ 1 n 2 ) n 3 1 + n 2 − n \mathop {\lim }\limits_{n \to \infty } \frac{{\sqrt[n]{{2024}}\left( {1 - \cos \frac{1}{{{n^2}}}} \right){n^3}}}{{\sqrt {1 + {n^2}} - n}} n→∞lim​1+n2 ​−nn2024 ​(1−cosn21​)n3​ …