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

协程,GIL全局解释器,互斥锁,线程池,Concurrent模块

进程是资源分配的最小单位,线程是CPU调度的最小单位。每一个进程中至少有一个线程。


Python对并发编程的支持


(1)多线程:threading,利用CPU和IO可以同时执行的原理,让CPU不会干巴巴等待IO完成。
(2)多进程:multiprocessing,利用多核CPU的能力,真正的并行执行任务。
(3)异步IO:asyncio,在单线程利用CPU和IO同时执行的原理,实现函数异步执行。
(4)使用Lock对资源加锁,防止冲突访问。
(5)使用Queue实现不同线程/进程之间的数据通信,实现生产者-消费者模式。
(6)使用线程池Pool/进程池Pool,简化线程/进程的任务提交、等待结束、获取结果。
(7)使用subprocess启动外部程序的进程,并进行输入输出交互。

Python并发编程有三种方式


多线程Thread、多进程Process、多协程Coroutine。

为什么要引入并发编程?


场景1:一个网络爬虫,按顺序爬取花了1小时,采用并发下载减少到20分钟!
场景2:一个APP应用,优化前每次打开页面需要3秒,采用异步并发提升到每次200毫秒!
引入并发,就是为了提升程序运行速度。

多线程、多进程、多协程的对比

怎样根据任务选择对应技术?

 

GIL全局解释器锁

        GIL全局解释器锁(Global Interpreter Lock)是一种在Python解释器中使用的机制,它的主要作用是防止同一时间内多个线程同时执行 Python 代码。

        在 Python 中,由于存在 GIL 锁的机制,因此在多线程执行 Python 代码时,同一时间只有一个线程能够占用 CPU 执行 Python 代码,其他线程将一直处于等待状态。

        这种机制有利于保证 Python 代码的稳定性和线程安全,但也带来了一定的性能损耗。因此,对于 CPU 密集型的 Python 应用程序,多线程并不能提高其运行速度。相反,对于 I/O 密集型的应用程序,多线程可以有效地提升其运行效率。

GIL步骤

在多线程环境中,Python 解释器按以下方式执行:

  1. 设置 GIL;
  2. 切换到一个线程去运行;
  3. 运行指定数量的字节码指令或者线程主动让出控制(可以调用 time.sleep(0));
  4. 把线程设置为睡眠状态;
  5. 解锁 GIL;
  6. 再次重复以上所有步骤。

在调用外部代码(如 C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于在这期间没有Python的字节码被运行,所以不会做线程切换)编写扩展的程序员可以主动解锁GIL。

GIL全局解释器相关背景

GIL锁就是保证在统一时刻只有一个线程执行,所有的线程必须拿到GIL锁才有执行权限

1. Python代码运行在解释器上嘛,有解释器来执行或者解释
2. Python解释器的种类:1、CPython  2、IPython 3、PyPy  4、Jython  5、IronPython
3. 当前市场使用的最多(95%)的解释器就是CPython解释器
4. GIL全局解释器锁是存在于CPython中
5. 结论是同一时刻只有一个线程在执行? 想避免的问题是,出现多个线程抢夺资源的情况比如:现在起一个线程,来回收垃圾数据,回收a=1这个变量,另外一个线程也要使用这个变量a,当垃圾回收线程还没没有把变量a回收完毕,另一个线程就来抢夺这个变量a使用。怎么避免的这个问题,那就是在Python这门语言设计之处,就直接在解释器上添加了一把锁,这把锁就是为了让统一时刻只有一个线程在执行,言外之意就是哪个线程想执行,就必须先拿到这把锁(GIL), 只有等到这个线程把GIL锁释放掉,别的线程才能拿到,然后具备了执行权限.

GIL全局解释器需要注意的问题

1. python有GIL锁的原因,同一个进程下多个线程实际上同一时刻,只有一个线程在执行2. 只有在python上开进程用的多,其他语言一般不开多进程,只开多线程就够了3. cpython解释器开多线程不能利用多核优势,只有开多进程才能利用多核优势,其他语言不存在这个问题4. 8核cpu电脑,充分利用起我这个8核,至少起8个线程,8条线程全是计算--->计算机cpu使用率是100%5. 如果不存在GIL锁,一个进程下,开启8个线程,它就能够充分利用cpu资源,跑满cpu6. cpython解释器中好多代码,模块都是基于GIL锁机制写起来的,改不了了---》我们不能有8个核,但我现在只能用1核,----》开启多进程---》每个进程下开启的线程,可以被多个cpu调度执行7. cpython解释器:io密集型使用多线程,计算密集型使用多进程

I / O密集型: 遇到io操作会切换cpu,假设你开了8个线程,8个线程都有io操作---》io操作不消耗cpu---》一段时间内看上去,其实8个线程都执行了, 选多线程好一些

计算密集型: 消耗cpu,如果开了8个线程,第一个线程会一直占着cpu,而不会调度到其他线程执行,其他7个线程根本没执行,所以我们开8个进程,每个进程有一个线程,8个进程下的线程会被8个cpu执行,从而效率高.


互斥锁

        互斥锁的作用:在多线程的情况下,同时执行一个数据,会发生数据错乱的问题,互斥锁可以防止这种情况发生。

n = 10
from threading import Lock
import timedef task(lock):lock.acquire()global ntemp = ntime.sleep(0.5)n = temp - 1lock.release()"""拿时间换空间,空间换时间 时间复杂度"""from threading import Threadif __name__ == '__main__':tt = []lock=Lock()for i in range(10):t = Thread(target=task, args=(lock, ))t.start()tt.append(t)for j in tt:j.join()print("主", n)

GIL锁,互斥锁 面试题

面试题:既然有了GIL锁,为什么还要互斥锁? (多线程下)


       举例比如:我起了2个线程,来执行a=a+1,a一开始是0
       1. 第一个线程来了,拿到a=0,开始执行a=a+1,这个时候结果a就是1了
       2. 第一个线程得到的结果1还没有赋值回去给a,这个时候,第二个线程来了,拿到的a是             0,继续执行, a=a+1结果还是1
       3. 加了互斥锁,就能够解决多线程下操作同一个数据,发生错乱的问题

线程队列(线程里使用队列)

为什么线程中还有使用队列?


        同一个进程下多个线程数据是共享的,为什么先同一个进程下还会去使用队列呢
因为队列是管道 + 锁,所以用队列还是为了保证数据的安全
 

程队列:1. 先进先出2. 后进先出3. 优先级的队列from multiprocessing import Queue"""线程队列"""import queue
queue.Queue()# queue.Queue 的缺点是它的实现涉及到多个锁和条件变量,因此可能会影响性能和内存效率。
import queueq=queue.Queue() # 无限大、
q.put('first')
q.put('second')
q.put('third')
q.put('third')print(q.get())
print(q.get())
print(q.get())## 后进先出
import queue# Lifo:last in first out
q=queue.LifoQueue()
q.put('first')
q.put('second')
q.put('third')print(q.get())
print(q.get())
print(q.get())## 优先级队列
import queueq=queue.PriorityQueue()
#put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
q.put((20,'a'))
q.put((10,'b'))
q.put((30,'c'))print(q.get())
print(q.get())
print(q.get())
'''
结果(数字越小优先级越高,优先级高的优先出队):
(10, 'b')
(20, 'a')
(30, 'c')
'''

进程池和线程池的使用

:池子、容器类型,可以盛放多个元素

进程池:提前定义好一个池子,然后,往这个池子里面添加进程,以后,只需要往这个进程池里面丢任务就行了,然后,有这个进程池里面的任意一个进程来执行任务

线程池:提前定义好一个池子,然后,往这个池子里面添加线程,以后,只需要往这个线程池里面丢任务就行了,然后,有这个线程池里面的任意一个线程来执行任务

def task(n, m):return n+mdef task1():return {'username':'kevin', 'password':123}
"""开进程池"""
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutordef callback(res):print(res) # Future at 0x1ed5a5e5610 state=finished returned int>print(res.result()) # 3def callback1(res):print(res) # Future at 0x1ed5a5e5610 state=finished returned int>print(res.result()) # {'username': 'kevin', 'password': 123}print(res.result().get('username'))
if __name__ == '__main__':pool=ProcessPoolExecutor(3) # 定义一个进程池,里面有3个进程## 2. 往池子里面丢任务pool.submit(task, m=1, n=2).add_done_callback(callback)pool.submit(task1).add_done_callback(callback1)pool.shutdown()  # join + closeprint(123)

进程池和线程池有什么好处呢? 

(1)降低资源消耗。通过重复利用已创建的线程降低线程创建、销毁线程造成的消耗。
(2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
(3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控。


Concurrent.futures模块(爬虫)

模块介绍

concurrent.futures模块提供了高度封装的异步调用接口

ThreadPoolExecutor:线程池,提供异步调用

ProcessPoolExecutor:进程池,提供异步调用

Both implement the same interface, which is defined by the abstract Executor class.

基本方法

submit(fn, *args, **kwargs):异步提交任务

map(func, *iterables, timeout=None, chunksize=1):取代for循环submit的操作

shutdown(wait=True):相当于进程池的pool.close()+pool.join()操作

  • wait=True,等待池内所有任务执行完毕回收完资源后才继续
  • wait=False,立即返回,并不会等待池内的任务执行完毕
  • 但不管wait参数为何值,整个程序都会等到所有任务执行完毕
  • submit和map必须在shutdown之前

result(timeout=None):取得结果

add_done_callback(fn):回调函数

done():判断某一个线程是否完成

cancle():取消某个任务

ThreadPoolExecutor线程池


常用函数


        将函数提交到线程池里面运行的时候,会自动创建Future对象并返回。这个Future对象里面就包含了函数的执行状态(比如此时是处于暂停、运行中还是完成等)。并且函数在执行完毕之后,还会调用future.set_result将自身的返回值设置进去。
        (1)创建一个线程池,可以指定max_workers参数,表示最多创建多少个线程。如果不指定,那么每提交一个函数,都会为其创建一个线程。

在启动线程池的时候,肯定是需要设置容量的,不然处理几千个函数要开启几千个线程。

        (2)通过submit即可将函数提交到线程池,一旦提交,就会立刻运行。因为开启了一个新的线程,主线程会继续往下执行。至于submit的参数,按照函数名,对应参数提交即可。

        (3)future相当于一个容器,包含了内部函数的执行状态。

        (4)函数执行完毕时,会将返回值设置在future里,也就是说一旦执行了 future.set_result,那么就表示函数执行完毕了,然后外界可以调用result拿到返回值。
 

from concurrent.futures import ThreadPoolExecutor
import timedef task(name, n):time.sleep(n)return f"{name} 睡了 {n} 秒"executor = ThreadPoolExecutor()
future = executor.submit(task, "屏幕前的你", 3)print(future)  # <Future at 0x7fbf701726d0 state=running
print(future.running())  # 函数是否正在运行中True
print(future.done())  # 函数是否执行完毕Falsetime.sleep(3)  # 主程序也sleep 3秒,显然此时函数已经执行完毕了print(future)  # <Future at 0x7fbf701726d0 state=finished returned str>返回值类型是str
print(future.running())  # False
print(future.done())  # Trueprint(future.result())

多线程爬取网页

import requestsdef get_page(url):res=requests.get(url)name=url.rsplit('/')[-1]+'.html'return {'name':name,'text':res.content}def call_back(fut):print(fut.result()['name'])with open(fut.result()['name'],'wb') as f:f.write(fut.result()['text'])if __name__ == '__main__':pool=ThreadPoolExecutor(2)urls=['http://www.baidu.com','http://www.cnblogs.com','http://www.taobao.com']for url in urls:pool.submit(get_page,url).add_done_callback(call_back)

协程理论

核心理解:切换是程序员级别的切换,我们自己切,不是操作系统切的

协程的本质:最大效率的利用计算机的CPU资源,欺骗计算机,让计算机cpu一直保持工作状态

协程:是单线程下的并发,又称微线程,纤程。英文名Coroutine。一句话说明什么是协程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。

需要强调的是:

  1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,切换其他线程运行)
  2. 单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效率(!!!非io操作的切换与效率无关)

对比操作系统控制线程的切换,用户在单线程内控制协程的切换。

优点如下:

  1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
  2. 单线程内就可以实现并发的效果,最大限度地利用cpu

缺点如下:

  1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
  2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程

总结协程特点

  1. 必须在只有一个单线程里实现并发
  2. 修改共享数据不需加锁
  3. 用户程序里自己保存多个控制流的上下文栈
  4. 附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))

协程之greenlet模块

一、安装模块

安装:pip3 install greenlet

二、greenlet实现状态切换

from greenlet import greenletdef eat(name):print('%s eat 1' %name)g2.switch('nick')print('%s eat 2' %name)g2.switch()
def play(name):print('%s play 1' %name)g1.switch()print('%s play 2' %name)g1=greenlet(eat)
g2=greenlet(play)g1.switch('nick')#可以在第一次switch时传入参数,以后都不需要

单纯的切换(在没有io的情况下或者没有重复开辟内存空间的操作),反而会降低程序的执行速度。

三、效率对比

#顺序执行
import time
def f1():res=1for i in range(100000000):res+=idef f2():res=1for i in range(100000000):res*=istart=time.time()
f1()
f2()
stop=time.time()
print('run time is %s' %(stop-start)) #10.985628366470337#切换
from greenlet import greenlet
import time
def f1():res=1for i in range(100000000):res+=ig2.switch()def f2():res=1for i in range(100000000):res*=ig1.switch()start=time.time()
g1=greenlet(f1)
g2=greenlet(f2)
g1.switch()
stop=time.time()
print('run time is %s' %(stop-start)) # 52.763017892837524

greenlet只是提供了一种比generator更加便捷的切换方式,当切到一个任务执行时如果遇到io,那就原地阻塞,仍然是没有解决遇到IO自动切换来提升效率的问题。

单线程里的这20个任务的代码通常会既有计算操作又有阻塞操作,我们完全可以在执行任务1时遇到阻塞,就利用阻塞的时间去执行任务2…如此,才能提高效率,这就用到了Gevent模块。


协程之gevent模块

1 猴子补丁

1,这个词原来为Guerrilla Patch,杂牌军、游击队,说明这部分不是原装的,在英文里guerilla发音和gorllia(猩猩)相似,再后来就写了monkey(猴子)。

2,还有一种解释是说由于这种方式将原来的代码弄乱了(messing with it),在英文里叫monkeying about(顽皮的),所以叫做Monkey Patch。

1.1 猴子补丁的功能(一切皆对象)

        拥有在模块运行时替换的功能, 例如: 一个函数对象赋值给另外一个函数对象(把函数原本的执行的功能给替换了)

class Monkey():def play(self):print('猴子在玩')class Dog():def play(self):print('狗子在玩')
m=Monkey()
m.play()
m.play=Dog().play
m.play()

1.2 monkey patch的应用场景

        这里有一个比较实用的例子,很多用到import json, 后来发现ujson性能更高,如果觉得把每个文件的import json改成import ujson as json成本较高, 或者说想测试一下ujson替换是否符合预期, 只需要在入口加上:

import json
import ujsondef monkey_patch_json():json.__name__ = 'ujson'json.dumps = ujson.dumpsjson.loads = ujson.loads
monkey_patch_json()
aa=json.dumps({'name':'lqz','age':19})
print(aa)

1.3 Gevent介绍

Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。 

 用法

#用法
g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的g2=gevent.spawn(func2)g1.join() #等待g1结束g2.join() #等待g2结束#或者上述两步合作一步:gevent.joinall([g1,g2])g1.value#拿到func1的返回值

示例1(遇到io自动切)

import gevent
def eat(name):print('%s eat 1' %name)gevent.sleep(2)print('%s eat 2' %name)def play(name):print('%s play 1' %name)gevent.sleep(1)print('%s play 2' %name)g1=gevent.spawn(eat,'lqz')
g2=gevent.spawn(play,name='lqz')
g1.join()
g2.join()
#或者gevent.joinall([g1,g2])
print('主')

示例二 

'''
上例gevent.sleep(2)模拟的是gevent可以识别的io阻塞,而time.sleep(2)或其他的阻塞,gevent是不能直接识别的需要用下面一行代码,打补丁,就可以识别了from gevent import monkey;monkey.patch_all()必须放到被打补丁者的前面,如time,socket模块之前或者我们干脆记忆成:要用gevent,需要将from gevent import monkey;monkey.patch_all()放到文件的开头
'''
from gevent import monkey;monkey.patch_all()import gevent
import time
def eat():print('eat food 1')time.sleep(2)print('eat food 2')def play():print('play 1')time.sleep(1)print('play 2')g1=gevent.spawn(eat)
g2=gevent.spawn(play_phone)
gevent.joinall([g1,g2])
print('主')# 我们可以用threading.current_thread().getName()来查看每个g1和g2,查看的结果为DummyThread-n,即假线程

协程实现高并发

服务端:

服务端:
from gevent import monkey;monkey.patch_all()
import gevent
from socket import socket
# from multiprocessing import Process
from threading import Threaddef talk(conn):while True:try:data = conn.recv(1024)if len(data) == 0: breakprint(data)conn.send(data.upper())except Exception as e:print(e)conn.close()def server(ip, port):server = socket()server.bind((ip, port))server.listen(5)while True:conn, addr = server.accept()# t=Process(target=talk,args=(conn,))# t=Thread(target=talk,args=(conn,))# t.start()gevent.spawn(talk, conn)if __name__ == '__main__':g1 = gevent.spawn(server, '127.0.0.1', 8080)g1.join()

客户端:

客户端:import socket
from threading import current_thread, Threaddef socket_client():cli = socket.socket()cli.connect(('127.0.0.1', 8080))while True:ss = '%s say hello' % current_thread().getName()cli.send(ss.encode('utf-8'))data = cli.recv(1024)print(data)for i in range(5000):t = Thread(target=socket_client)t.start()

END


相关文章:

协程,GIL全局解释器,互斥锁,线程池,Concurrent模块

进程是资源分配的最小单位&#xff0c;线程是CPU调度的最小单位。每一个进程中至少有一个线程。 Python对并发编程的支持 (1)多线程&#xff1a;threading&#xff0c;利用CPU和IO可以同时执行的原理&#xff0c;让CPU不会干巴巴等待IO完成。 (2)多进程&#xff1a;multiproces…...

MAPEFFECT代码在传奇中有何作用如何运用

今天介绍一下MAPEFFECT的作用和使用方法&#xff0c;可以实现的效果比如进入游戏或者某个地图显示特效&#xff0c;或者显示地图名称&#xff0c;提示信息等等用到的命令就是MAPEFFECT。 使用方法是 在QManage.txt中找到 [Startup] 在下面增加如下代码 #if #act MAPEFFECT 11…...

Godot 官方2D C#重构(1):雪花碰撞

前言 Godot 官方 教程 Godot 2d 官方案例C#重构 专栏 Godot 2d 重构 github地址 实现效果 难点介绍 Godot GDScript和C# 对应关系大部分靠猜 文件导入 资源地址&#xff1a;默认为res://开头2D贴图导入类型&#xff1a;Texture2D public Texture2D Bullet_Image new Textu…...

计算机基础知识35

进程和线程的比较 1. 进程的开销比线程的开销大很多 2. 进程之间的数据是隔离的&#xff0c;但是&#xff0c;线程之间的数据不隔离 3. 多个进程间的线程数据不共享----->让进程通信(IPC)---->进程下的线程也通信了---->队列 GIL全局解释器锁(重要理论) # 虽然一个进程…...

VulnHub mrRobot

一、信息收集 1.访问地址 没啥信息&#xff0c;尝试扫下目录 2.目录扫描 key1 发现有wp-admin/和robots.txt robots.txt里面还拿到了一个密码字典&#xff0c;猜测是爆破wp的网站账号密码的 3.访问wp-admin/ ┌──(root&#x1f480;kali)-[~/桌面] └─# sort -u fsoci…...

【MATLAB第79期】基于MATLAB的数据抽样合集(sobol、LHS、Halton、正交、随机函数)更新中

【MATLAB第79期】基于MATLAB的数据抽样合集&#xff08;sobol、LHS、Halton、正交、随机函数&#xff09;更新中 一、随机函数 1.指定区间随机生成数据&#xff08;小数&#xff09; [a b]区间随机数生成: Aa(b-a)rand(m,n) m&#xff1a;待生成矩阵A的行数 n: 待生成矩阵A…...

Lua快速入门教程

文章目录 1、Linux安装Lua2、语法练习2.1、变量2.2、循环2.3、函数2.4、数组2.5、迭代器2.6、Table操作2.7、Lua 模块与包2.8、加载机制2.9、Lua 元表(Metatable) 3、Lua 协同程序(coroutine)4、文件IO操作4.1、简单模式4.2、完全模式 5、错误处理 内容来源菜鸟教程&#xff0c…...

html资源提示符

前言&#xff1a;正常dom解析 中遇到script标签 &#xff0c;会暂停主线程 去下载js&#xff0c;拿到资源后&#xff0c;主线程再执行js。 那么主线程在等待网络线程下载这个空闲很浪费 解决方案&#xff1a; script标签增加属性 async defer 1.async <script src"./i…...

VR智能家居虚拟连接仿真培训系统重塑传统家居行业

家居行业基于对场景的打造及设计&#xff0c;拥有广阔前景&#xff0c;是众多行业里面成为最有可能进行元宇宙落地的应用场景之一。 家居行业十分注重场景的打造及设计&#xff0c;而元宇宙恰恰能通过将人工智能、虚拟现实、大数据、物联网等技术融合提升&#xff0c;带来身临其…...

Defects4j数据集安装及使用

0、常见问题 1. 所有配置完成后运行defects4j info -p Lang测试出现错误 Cant locate DBI.pm in INC (you may need to install the DBI module) (INC contains: /myproject/defects4j/framework/lib /myproject/defects4j/framework /myproject/defects4j/framework/core /m…...

vant_ CountDown倒计时

语法可以直接在官网查看 需求 后端返回的数据格式如下 [{"id": 1,"btn_text": "1","second": 0},{"id": 2,"btn_text": "1","second": 0}... ]之前约定second最多30s&#xff0c; 因此只需…...

spark集成hive

集群使用ambarihdp方式进行部署,集群的相关版本号如下所示: ambari版本 Version 2.7.4.0 HDP版本 HDP-3.1.4.0 hive版本 3.1.0 spark版本 2.3.0 集群前提条件: 1.Hdp、Spark、Hive都已部署好 2.Hive数据层建好&#xff0c;在Hdfs生成相应各层目录&#xff0c;后面配…...

提升微服务稳定性与性能:深入剖析Netflix Hystrix框架

说到 Netflix Hystrix 框架&#xff0c;一定离不开 com.netflix.hystrix.HystrixCommand&#xff0c;这个类是 Netflix 开源的 Hystrix 框架中的一个关键类&#xff0c;用于实现服务的容错和熔断功能。它主要用于将远程服务调用封装成一个独立的命令对象&#xff0c;以便于进行…...

IT运维管理系统在国有大型企业网络中的应用和可以解决的问题

随着国有大型企业业务的快速发展&#xff0c;网络运维管理面临着诸多挑战。本文将从问题概述、解决方案、监控易优势、实际案例和总结等方面阐述IT运维管理系统在国有大型企业网络中的应用和可以解决的问题。​IT运维管理系统&#xff1a;国有大型企业网络的变革者与解决之道 一…...

嵌入式实时操作系统的设计与开发 (线程操作学习)

在aCoral操作系统中&#xff0c;线程退出采用了和Linux一样的方式&#xff0c;线程函数不用死等或显示调用退出相关函数&#xff0c;也就是说用户不用担心函数执行完后的事情。 uc/OS II任务函数与退出 void test(void *ptr){Do_something();while(1); }void test(void *ptr)…...

竞赛 深度学习交通车辆流量分析 - 目标检测与跟踪 - python opencv

文章目录 0 前言1 课题背景2 实现效果3 DeepSORT车辆跟踪3.1 Deep SORT多目标跟踪算法3.2 算法流程 4 YOLOV5算法4.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; *…...

【RTOS学习】同步与互斥 | 队列

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《RTOS学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 同步与互斥 | 队列 &#x1f349;同步与互斥&#x1f366;同步&#x1f366;互斥 &#x1f349;队…...

Python订单生成器+队列+异步提高性能和容错

以下代码实现了一个订单生成器&#xff0c;使用 asyncio 和 aioredis 库实现了高并发地生成订单&#xff0c;并将新增订单异步更新到数据库。具体实现流程如下&#xff1a; 初始化 OrderGenerator 类。传入 Redis 服务器地址和并发数&#xff0c;在初始化函数中设置并发数和一…...

理德名人故事:全球投资之父-约翰.邓普顿

说到约翰‧邓普顿&#xff0c;我们就会想到他的很多标签。比如全球投资之父、史上最成功的基金经理等等。他是邓普顿集团的创始人&#xff0c;一直被誉为全球最具智慧以及最受尊崇的投资者之一。福布斯资本家杂志称他为"全球投资之父"及"历史上最成功的基金经理…...

微前端三:qiankun 协作开发和上线部署

我们先看qiankun怎么上线部署&#xff1a; 我这边用的是yaml 文件在 rancher上部署的&#xff1a; base是基座&#xff0c;这里每个应用都是一个服务&#xff0c;这个还是跟之前一样并没有区别&#xff0c;那如何在一个域名上挂载多个服务呢&#xff1f; 最开始我们主要是在in…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...

SpringAI实战:ChatModel智能对话全解

一、引言&#xff1a;Spring AI 与 Chat Model 的核心价值 &#x1f680; 在 Java 生态中集成大模型能力&#xff0c;Spring AI 提供了高效的解决方案 &#x1f916;。其中 Chat Model 作为核心交互组件&#xff0c;通过标准化接口简化了与大语言模型&#xff08;LLM&#xff0…...

LINUX编译vlc

下载 VideoLAN / VLC GitLab 选择最新的发布版本 准备 sudo apt install -y xcb bison sudo apt install -y autopoint sudo apt install -y autoconf automake libtool编译ffmpeg LINUX FFMPEG编译汇总&#xff08;最简化&#xff09;_底部的附件列表中】: ffmpeg - lzip…...

华硕电脑,全新的超频方式,无需进入BIOS

想要追求更佳性能释放 或探索更多可玩性的小伙伴&#xff0c; 可能会需要为你的电脑超频。 但我们常用的不论是BIOS里的超频&#xff0c; 还是Armoury Crate奥创智控中心超频&#xff0c; 每次调节都要重启&#xff0c;有点麻烦。 TurboV Core 全新的超频方案来了 4不规…...