Python协程详解:从基础到实战
协程是Python中实现并发编程的重要方式之一,它比线程更轻量级,能够高效处理I/O密集型任务。本文将全面介绍协程的概念、原理、实现方式以及与线程、进程的对比,包含完整的效率对比代码和详细说明,帮助Python开发者深入理解并掌握协程技术。
1. 协程基础概念
1.1 什么是协程
协程(Coroutine)是Python中另外一种实现多任务的方式,它是一种比线程更小的执行单元,占用更少的资源。协程之所以被称为执行单元,是因为它自带CPU上下文。这意味着只要在合适的时机,我们可以把一个协程切换到另一个协程,只要在这个过程中保存或恢复CPU上下文,程序就可以继续运行。
通俗地说:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行(注意不是通过调用函数的方式做到的),并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定。
1.2 为什么需要协程
在传统多线程编程中,我们知道:
-
进程是资源分配的最小单位
-
线程是CPU调度的最小单位
虽然多线程已经提高了CPU利用率,但创建和管理线程/进程需要消耗系统资源。随着对效率的追求不断提高,基于单线程实现并发成为一个新的课题,即只用一个主线程(很明显可利用的CPU只有一个)情况下实现并发。这样可以节省创建线程/进程所消耗的时间。
1.3 并发的本质
并发的本质可以概括为:切换+保存状态
CPU正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制):
-
该任务发生了阻塞(如I/O操作)
-
该任务计算的时间过长(时间片用完)
其中第二种情况并不能提升效率,只是为了让CPU能够"雨露均沾",实现看起来所有任务都被"同时"执行的效果。如果多个任务都是纯计算的,这种切换反而会降低效率。
2. 协程与线程的差异
在实现多任务时,线程切换从系统层面远不止保存和恢复CPU上下文这么简单。操作系统为了程序运行的高效性,每个线程都有自己缓存Cache等数据,操作系统还会帮你做这些数据的恢复操作。所以线程的切换非常耗性能。
相比之下,协程的切换只是单纯地操作CPU的上下文,所以一秒钟切换个上百万次系统都抗得住。具体差异如下:
| 特性 | 线程 | 协程 |
|---|---|---|
| 调度者 | 操作系统 | 用户程序 |
| 切换代价 | 高(涉及内核态切换) | 低(用户态切换) |
| 内存占用 | 较大(MB级) | 极小(KB级) |
| 并发数量 | 有限(千级) | 极高(百万级) |
| 数据同步 | 需要锁机制 | 无需加锁 |
3. Python协程的特点
-
必须在单线程里实现并发:协程的本质是单线程下的并发
-
修改共享数据不需加锁:因为是单线程,不存在竞争条件
-
用户程序自己保存多个控制流的上下文栈
-
自动I/O切换:一个协程遇到I/O操作自动切换到其它协程(需要gevent等模块支持)
4. Python协程的实现方式
4.1 yield模拟协程
Python中的生成器(generator)和yield关键字可以初步模拟协程的行为:
def consumer():while True:x = yield # 接收send发送的值print(f"处理数据: {x}")def producer():c = consumer()c.__next__() # 启动生成器for i in range(5):print(f"生产数据: {i}")c.send(i) # 发送数据给consumerproducer()
这段代码展示了生产者-消费者模型的基本协程实现。生产者通过send()方法将数据发送给消费者,消费者通过yield接收并处理数据。
4.2 Greenlet模块
Greenlet是一个更专业的协程实现,它提供了明确的切换方法:
from greenlet import greenlet
import timedef task1():print("执行任务1")gr2.switch() # 切换到任务2print("任务1继续执行")gr2.switch()def task2():print("执行任务2")gr1.switch() # 切换回任务1print("任务2继续执行")gr1 = greenlet(task1)
gr2 = greenlet(task2)
gr1.switch() # 启动任务1
Greenlet的优点是切换明确,缺点是需要手动切换,无法自动识别I/O阻塞。
4.3 Gevent模块
Gevent是基于Greenlet的更高级协程库,它能够自动处理I/O阻塞:
import gevent
from gevent import monkey
monkey.patch_all() # 打补丁,替换标准库中的阻塞式I/Odef fetch(url):print(f"获取 {url}")gevent.sleep(2) # 模拟I/O操作print(f"{url} 返回数据")def async_fetch():urls = ['url1', 'url2', 'url3']jobs = [gevent.spawn(fetch, url) for url in urls]gevent.joinall(jobs)async_fetch()
Gevent的关键点:
-
monkey.patch_all():替换Python标准库中的阻塞式I/O为Gevent的非阻塞版本 -
gevent.spawn():创建协程任务 -
gevent.joinall():等待所有协程完成
5. 协程效率对比测试
5.1 顺序执行 vs 协程执行
下面我们通过一个完整的例子来对比顺序执行和协程执行的效率差异:
from gevent import monkey
import gevent
import time
import requests# 打补丁
monkey.patch_all()# 测试URL
url = "https://www.baidu.com"# 顺序执行
def sequential_fetch():start = time.time()for i in range(5):print(f"顺序请求 {i} 开始")response = requests.get(url)print(f"顺序请求 {i} 完成,状态码: {response.status_code}")print(f"顺序执行总耗时: {time.time() - start:.2f}秒")# 协程执行
def coroutine_fetch():start = time.time()def fetch(i):print(f"协程请求 {i} 开始")response = requests.get(url)print(f"协程请求 {i} 完成,状态码: {response.status_code}")jobs = [gevent.spawn(fetch, i) for i in range(5)]gevent.joinall(jobs)print(f"协程执行总耗时: {time.time() - start:.2f}秒")# 执行测试
print("=== 顺序执行测试 ===")
sequential_fetch()print("\n=== 协程执行测试 ===")
coroutine_fetch()
执行结果分析:
-
顺序执行:每个请求依次执行,总耗时≈各请求耗时之和
-
协程执行:所有请求并发执行,总耗时≈最慢的单个请求耗时
5.2 线程 vs 协程效率对比
下面我们对比线程和协程在处理I/O密集型任务时的效率:
import threading
import time
import requests
from gevent import monkey
import geventmonkey.patch_all()
url = "https://www.baidu.com"
n = 10 # 并发数量# 线程方式
def thread_fetch():start = time.time()def fetch(i):response = requests.get(url)print(f"线程 {i} 完成")threads = []for i in range(n):t = threading.Thread(target=fetch, args=(i,))t.start()threads.append(t)for t in threads:t.join()print(f"线程方式总耗时: {time.time() - start:.2f}秒")# 协程方式
def gevent_fetch():start = time.time()def fetch(i):response = requests.get(url)print(f"协程 {i} 完成")jobs = [gevent.spawn(fetch, i) for i in range(n)]gevent.joinall(jobs)print(f"协程方式总耗时: {time.time() - start:.2f}秒")# 执行测试
print("=== 线程方式测试 ===")
thread_fetch()print("\n=== 协程方式测试 ===")
gevent_fetch()
执行结果分析:
-
线程方式:创建线程有一定开销,线程切换需要内核参与
-
协程方式:协程创建和切换开销极小,完全在用户空间完成
5.3 不同并发量下的效率对比
我们测试不同并发量下协程的执行效率:
import time
from gevent import monkey
import gevent
import requestsmonkey.patch_all()def test_concurrency(concurrency):print(f"\n=== 并发数: {concurrency} ===")start = time.time()def task(i):requests.get("https://www.baidu.com")print(f"任务 {i} 完成", end=" | ")jobs = [gevent.spawn(task, i) for i in range(concurrency)]gevent.joinall(jobs)elapsed = time.time() - startprint(f"\n并发数 {concurrency} 总耗时: {elapsed:.2f}秒")return elapsed# 测试不同并发量
concurrency_levels = [10, 50, 100, 200, 500]
results = {}
for level in concurrency_levels:results[level] = test_concurrency(level)# 打印结果对比
print("\n=== 结果汇总 ===")
for level, time_cost in results.items():print(f"并发数 {level}: {time_cost:.2f}秒")
预期结果:
-
小并发量时总耗时接近单个请求耗时
-
随着并发量增加,总耗时增长缓慢
-
协程可以轻松支持上千并发
6. 协程的实际应用
6.1 网络爬虫
协程特别适合网络爬虫这种I/O密集型应用:
import gevent
from gevent import monkey
monkey.patch_all()
import requests
from urllib.parse import urljoin
from bs4 import BeautifulSoupbase_url = "https://www.example.com"
visited = set()def crawler(url):if url in visited:returnvisited.add(url)try:print(f"抓取: {url}")response = requests.get(url)soup = BeautifulSoup(response.text, 'html.parser')# 处理页面内容...print(f"从 {url} 找到 {len(soup.find_all('a'))} 个链接")# 发现新链接links = [urljoin(base_url, a['href']) for a in soup.find_all('a', href=True)]# 创建协程抓取新链接jobs = [gevent.spawn(crawler, link) for link in links if link.startswith(base_url)]gevent.joinall(jobs)except Exception as e:print(f"抓取 {url} 出错: {e}")# 开始抓取
crawler(base_url)
6.2 Web服务器
使用协程可以轻松实现高并发的Web服务器:
from gevent.pywsgi import WSGIServer
from gevent import monkey
monkey.patch_all()def application(env, start_response):path = env['PATH_INFO']if path == '/':start_response('200 OK', [('Content-Type', 'text/html')])return [b"<h1>Welcome</h1><p>Hello from Gevent server!</p>"]elif path == '/api/data':# 模拟数据库查询gevent.sleep(1)start_response('200 OK', [('Content-Type', 'application/json')])return [b'{"data": [1, 2, 3]}']else:start_response('404 Not Found', [('Content-Type', 'text/html')])return [b"<h1>404 Not Found</h1>"]if __name__ == '__main__':print("Server running on http://localhost:8000")server = WSGIServer(('0.0.0.0', 8000), application)server.serve_forever()
6.3 数据库操作
协程化的数据库操作可以显著提高并发性能:
import gevent
from gevent import monkey
monkey.patch_all()
import pymysql
from DBUtils.PooledDB import PooledDB# 创建数据库连接池
db_pool = PooledDB(creator=pymysql,host='localhost',user='root',password='123456',db='test',maxconnections=20
)def query_user(user_id):conn = db_pool.connection()try:with conn.cursor() as cursor:sql = "SELECT * FROM users WHERE id = %s"cursor.execute(sql, (user_id,))result = cursor.fetchone()print(f"查询到用户 {user_id}: {result}")return resultfinally:conn.close()# 并发查询多个用户
user_ids = [1, 2, 3, 4, 5]
jobs = [gevent.spawn(query_user, uid) for uid in user_ids]
gevent.joinall(jobs)
7. 协程与多线程、多进程的对比
7.1 完整对比表格
| 特性 | 进程 | 线程 | 协程 |
|---|---|---|---|
| 创建开销 | 大(10+MB) | 中(1MB左右) | 极小(几KB) |
| 切换开销 | 高(微秒级) | 中(微秒级) | 低(纳秒级) |
| 内存占用 | 独立内存空间 | 共享进程内存 | 共享线程内存 |
| 数据共享 | IPC机制 | 全局变量 | 全局变量 |
| 并发数量 | 数十个 | 数百个 | 数十万个 |
| CPU利用 | 多核 | 多核(受GIL限制) | 单核 |
| 适用场景 | CPU密集型 | I/O+少量CPU | I/O密集型 |
| 编程复杂度 | 高 | 中(需同步) | 低 |
| 稳定性 | 高(隔离性好) | 中(一个线程崩溃影响整个进程) | 中(一个协程出错可能影响其他协程) |
7.2 性能对比测试
下面我们通过一个完整的测试来对比进程、线程和协程的性能差异:
import time
import multiprocessing
import threading
from gevent import monkey
import geventmonkey.patch_all()# 测试任务:模拟I/O密集型操作
def task(n):gevent.sleep(1) # 模拟I/O操作return n * n# 进程方式
def process_way():start = time.time()pool = multiprocessing.Pool(processes=10)results = pool.map(task, range(10))pool.close()pool.join()print(f"进程方式 结果: {results} 耗时: {time.time() - start:.2f}秒")# 线程方式
def thread_way():start = time.time()threads = []results = []def worker(n):results.append(task(n))for i in range(10):t = threading.Thread(target=worker, args=(i,))t.start()threads.append(t)for t in threads:t.join()print(f"线程方式 结果: {results} 耗时: {time.time() - start:.2f}秒")# 协程方式
def coroutine_way():start = time.time()jobs = [gevent.spawn(task, i) for i in range(10)]gevent.joinall(jobs)results = [job.value for job in jobs]print(f"协程方式 结果: {results} 耗时: {time.time() - start:.2f}秒")# 执行测试
print("=== 进程方式测试 ===")
process_way()print("\n=== 线程方式测试 ===")
thread_way()print("\n=== 协程方式测试 ===")
coroutine_way()
预期结果:
-
进程方式:耗时≈1秒,但创建进程开销大
-
线程方式:耗时≈1秒,受GIL影响
-
协程方式:耗时≈1秒,但资源占用最少
8. 协程最佳实践
8.1 避免CPU密集型任务
协程不适合纯CPU计算任务,下面是一个反面例子:
import time
from gevent import monkey
import geventmonkey.patch_all()# CPU密集型任务
def cpu_intensive(n):result = 0for i in range(n):result += i * ireturn result# 测试协程执行CPU密集型任务
def test_coroutine_cpu():start = time.time()jobs = [gevent.spawn(cpu_intensive, 1000000) for _ in range(10)]gevent.joinall(jobs)print(f"协程执行CPU密集型任务耗时: {time.time() - start:.2f}秒")# 测试顺序执行
def test_sequential_cpu():start = time.time()results = [cpu_intensive(1000000) for _ in range(10)]print(f"顺序执行CPU密集型任务耗时: {time.time() - start:.2f}秒")print("=== CPU密集型任务测试 ===")
test_coroutine_cpu()
test_sequential_cpu()
结论:对于CPU密集型任务,协程不会带来性能提升,反而可能因为切换开销而降低性能。
8.2 合理控制并发量
虽然协程很轻量,但也需要合理控制并发量:
from gevent import monkey
import gevent
import requests
import timemonkey.patch_all()def fetch(url, semaphore):with semaphore: # 控制并发量print(f"开始请求 {url}")response = requests.get(url)print(f"完成请求 {url} 状态码: {response.status_code}")def controlled_concurrency(url, concurrency=10, total=100):start = time.time()semaphore = gevent.pool.Semaphore(concurrency) # 并发信号量jobs = [gevent.spawn(fetch, url, semaphore) for _ in range(total)]gevent.joinall(jobs)print(f"总请求数: {total} 并发数: {concurrency} 总耗时: {time.time() - start:.2f}秒")# 测试不同并发控制
url = "https://www.baidu.com"
controlled_concurrency(url, concurrency=10, total=100)
controlled_concurrency(url, concurrency=20, total=100)
controlled_concurrency(url, concurrency=50, total=100)
8.3 异常处理
正确处理协程中的异常:
import gevent
from gevent import monkey
monkey.patch_all()def successful_task():return "成功完成任务"def failing_task():raise Exception("任务执行失败")def handle_exceptions():jobs = [gevent.spawn(successful_task),gevent.spawn(failing_task),gevent.spawn(successful_task)]gevent.joinall(jobs)for job in jobs:if job.successful():print(f"任务结果: {job.value}")else:print(f"任务失败: {job.exception}")print("=== 异常处理测试 ===")
handle_exceptions()
9. 常见问题解答
Q: 协程能利用多核CPU吗?
A: 单个协程不能,因为它在单线程中运行。但可以通过多进程+协程的方式利用多核,例如每个进程运行一个事件循环。
Q: 协程会取代线程吗?
A: 不会完全取代。协程适合I/O密集型场景,线程适合需要利用多核或与C扩展交互的场景。最佳实践是根据需求选择合适的并发模型。
Q: Gevent的monkey patch安全吗?
A: 在大多数情况下是安全的,但应注意:
-
尽早调用
monkey.patch_all() -
避免与其他修改标准库的库同时使用
-
生产环境中先充分测试
Q: 如何调试协程程序?
A: 调试协程程序可以使用:
-
打印日志
-
gevent.getcurrent()获取当前协程 -
使用支持协程的调试器如PyCharm专业版
10. 总结
协程是Python中强大的并发编程工具,特别适合I/O密集型应用。通过本文的完整介绍和代码示例,我们了解了:
-
协程的基本概念和原理
-
Python中实现协程的三种方式:yield、greenlet、gevent
-
完整的效率对比测试代码和结果分析
-
协程在实际项目中的应用场景
-
协程与线程、进程的详细对比
-
协程编程的最佳实践和常见问题
掌握协程技术可以让你的Python程序在处理高并发时更加高效和优雅。希望本文能帮助你全面理解Python协程,并在实际项目中灵活应用。
相关文章:
Python协程详解:从基础到实战
协程是Python中实现并发编程的重要方式之一,它比线程更轻量级,能够高效处理I/O密集型任务。本文将全面介绍协程的概念、原理、实现方式以及与线程、进程的对比,包含完整的效率对比代码和详细说明,帮助Python开发者深入理解并掌握协…...
学习笔记(C++篇)--- Day 4
目录 1.赋值运算符重载 1.1 运算符重载 1.2 赋值运算符重载 1.3 日期类实现 1.赋值运算符重载 1.1 运算符重载 ①当运算符被用于类类型的对象时,C语言允许我们通过通过运算符重载的形式指定新的含义。C规定类类型对象使用运算符时,必须转换成调用对…...
空闲列表:回收和再利用
空闲列表:回收和再利用 手动与自动内存管理 手动管理:程序员需要明确地分配和释放内存。自动管理:例如使用垃圾收集器(GC),它能够自动检测并回收未使用的对象,不需要程序员干预。 对于某些数据结构如B树,…...
504 nginx解决方案
当遇到 504 Gateway Time-out 错误时,通常是因为 Nginx 作为反向代理等待后端服务(如 PHP-FPM、Java 应用等)响应的时间超过了预设的超时阈值。以下是详细的解决方案,结合知识库中的信息整理而成: 一、核心原因分析 后…...
【消息队列RocketMQ】五、RocketMQ 实战应用与生态拓展
本篇文章主要将结合前面几篇文章的基础讲解,来演示RocketMQ的实际场景中的应用。 一、RocketMQ 实战应用场景 1.1 电商系统中的应用 在电商系统中,RocketMQ 承担着重要角色。以双十一大促活动为例,短时间内会产生海量的订单请求、库存…...
volatile怎么保证可见性和有序性?(个人理解)
volatile怎么保证可见性和有序性? volatile变量会在字段修饰符中显示ACC_VOLATILE。通过插入内存屏障指令,禁止指令重排序。不管前面与后面任何指令,都不能与内存屏障指令进行重排,保证前后的指令按顺序执行 。同时保证数据修改的…...
计算机组成与体系结构:直接内存映射(Direct Memory Mapping)
目录 CPU地址怎么找到真实的数据? 内存映射的基本单位和结构 1. Pages(页)——虚拟地址空间的基本单位 2. Frames(页框)——物理内存空间的基本单位 3. Blocks(块)——主存和缓存之间的数据…...
RAGFlow:构建高效检索增强生成流程的技术解析
引言 在当今信息爆炸的时代,如何从海量数据中快速准确地获取所需信息并生成高质量内容已成为人工智能领域的重要挑战。检索增强生成(Retrieval-Augmented Generation, RAG)技术应运而生,它将信息检索与大型语言模型(L…...
STM32提高篇: 蓝牙通讯
STM32提高篇: 蓝牙通讯 一.蓝牙通讯介绍1.蓝牙技术类型 二.蓝牙协议栈1.蓝牙芯片架构2.BLE低功耗蓝牙协议栈框架 三.ESP32-C3中的蓝牙功能1.广播2.扫描3.通讯 四.发送和接收 一.蓝牙通讯介绍 蓝牙,是一种利用低功率无线电,支持设备短距离通信的无线电技…...
SpringMVC处理请求映射路径和接收参数
目录 springmvc处理请求映射路径 案例:访问 OrderController类的pirntUser方法报错:java.lang.IllegalStateException:映射不明确 核心错误信息 springmvc接收参数 一 ,常见的字符串和数字类型的参数接收方式 1.1 请求路径的…...
高质量学术引言如何妙用ChatGPT?如何写提示词
目录 1、引言究竟是什么? 2、引言如何构建?? 在学术写作领域,巧妙利用人工智能来构建文章的引言和理论框架是一个尚待探索的领域。小编在这篇文章中探讨一种独特的方法,即利用 ChatGPT 作为工具来构建引言和理论框架…...
【程序员 NLP 入门】词嵌入 - 上下文中的窗口大小是什么意思? (★小白必会版★)
🌟 嗨,你好,我是 青松 ! 🌈 希望用我的经验,让“程序猿”的AI学习之路走的更容易些,若我的经验能为你前行的道路增添一丝轻松,我将倍感荣幸!共勉~ 【程序员 NLP 入门】词…...
从物理到预测:数据驱动的深度学习的结构化探索及AI推理
在当今科学探索的时代,理解的前沿不再仅仅存在于我们书写的方程式中,也存在于我们收集的数据和构建的模型中。在物理学和机器学习的交汇处,一个快速发展的领域正在兴起,它不仅观察宇宙,更是在学习宇宙。 AI推理 我们…...
各种各样的bug合集
一、连不上数据库db 1.可能是密码一大包东西不对; 2.可能是里面某个port和数据库不一样(针对于修改了数据库但是连不上的情况); 3.可能是git代码没拉对,再拉一下代码。❤ 二、没有这个包 可能是可以#注释掉。❤ …...
大模型AI的“双刃剑“:数据安全与可靠性挑战与破局之道
在数字经济蓬勃发展的浪潮中,数据要素已然成为驱动经济社会创新发展的核心引擎。从智能制造到智慧城市,从电子商务到金融科技,数据要素的深度融合与广泛应用,正以前所未有的力量重塑着产业格局与经济形态。 然而,随着…...
如何使用 CompletableFuture、Function 和 Optional 优雅地处理异步编程?
当异步遇上函数式编程,代码变得更优雅 在日常开发中,很多时候我们需要处理异步任务、函数转换和空值检查。传统的回调方式和空值判断常常让代码看起来繁琐而难以维护。幸运的是,Java 提供了 CompletableFuture、Function 和 Optional&#x…...
基于大模型的结肠癌全病程预测与诊疗方案研究
目录 一、引言 1.1 研究背景与意义 1.2 研究目的与创新点 二、结肠癌概述 2.1 流行病学特征 2.2 发病机制与危险因素 2.3 临床症状与诊断方法 三、大模型技术原理与应用现状 3.1 大模型的基本原理 3.2 在医疗领域的应用情况 3.3 在结肠癌预测中的潜力分析 四、术前…...
操作系统概述与安装
主流操作系统概述 信创平台概述 虚拟机软件介绍与安装 windows server 安装 centos7 安装 银河麒麟V10 安装 一:主流服务器操作系统 (1)Windows Server 发展历程: 1993年推出第一代 WindowsNT(企业级内核&am…...
算法设计与分析(基础)
问题列表 一、 算法的定义与特征,算法设计的基本步骤二、 算法分析的目的是什么?如何评价算法,如何度量算法的复杂性?三、 递归算法、分治法、贪婪法、动态规划法、回溯法的基本思想方法。四、 同一个问题,如TSP&#…...
多线程(线程安全)
一、线程安全的风险来源 1.1 后厨的「订单撞单」现象 场景:两服务员同时录入客人点单到同一个菜单本 问题: 订单可能被覆盖菜品数量统计错误 Java中的表现: public class OrderServlet extends HttpServlet {private int totalOrders 0…...
开发了一个b站视频音频提取器
B站资源提取器-说明书 一、功能说明 本程序可自动解密并提取B站客户端缓存的视频资源,支持以下功能: - 自动识别视频缓存目录 - 将加密的.m4s音频文件转换为标准MP3格式 - 将加密的.m4s视频文件转换为标准MP4格式(合并音视频流)…...
基于javaweb的SpringBoot校园服务平台系统设计与实现(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...
北京SMT贴片加工工艺优化要点
内容概要 在北京地区SMT贴片加工领域,工艺优化是实现高可靠电子组装的系统性工程。本文以精密化生产需求为导向,围绕制程关键节点展开技术剖析,从钢网印刷的锡膏成型控制到贴装环节的视觉定位精度,逐步构建全流程优化模型。通过分…...
PHYBench:首个大规模物理场景下的复杂推理能力评估基准
2025-04-23, 由北京大学物理学院和人工智能研究所等机构共同创建的 PHYBench 数据集,这是一个专门用于评估大型语言模型在物理场景下的复杂推理能力的高质量基准。该数据集包含 500 道精心策划的物理问题,覆盖力学、电磁学、热力学、光学、现代物理和高级…...
将输入帧上下文打包到下一个帧的预测模型中用于视频生成
Paper Title: Packing Input Frame Context in Next-Frame Prediction Models for Video Generation 论文发布于2025年4月17日 Abstract部分 在这篇论文中,FramePack是一种新提出的网络结构,旨在解决视频生成中的两个主要问题:遗忘和漂移。 具体来说,遗忘指的是在生成视…...
使用localStorage的方式存储数据,刷新之后,无用户消息,需要重新登录,,localStorage 与 sessionStorage 的区别
1 localStorage 与 sessionStorage 的区别: 特性localStoragesessionStorage存储时长永久存储,除非手动删除或者清空浏览器缓存会话存储,浏览器关闭后数据丢失数据生命周期持久存在,直到被明确删除(即使关闭浏览器也不会消失)当前会话结束后数据自动清空(关闭标签页或浏…...
第15章:MCP服务端项目开发实战:性能优化
第15章:MCP服务端项目开发实战:性能优化 在构建和部署 MCP(Memory, Context, Planning)驱动的 AI Agent 系统时,性能和可扩展性是关键的考量因素。随着用户量、数据量和交互复杂度的增加,系统需要能够高效地处理请求,并能够平滑地扩展以应对更高的负载。本章将探讨 MCP…...
MOA Transformer:一种基于多尺度自注意力机制的图像分类网络
MOA Transformer:一种基于多尺度自注意力机制的图像分类网络 引言 近年来,Transformer 架构在自然语言处理领域取得了巨大的成功,并逐渐扩展到计算机视觉领域。Swin Transformer 就是其中一个典型的成功案例。它通过引入“无卷积”架构&…...
Red:1靶场环境部署及其渗透测试笔记(Vulnhub )
环境介绍: 靶机下载: https://download.vulnhub.com/red/Red.ova 本次实验的环境需要用到VirtualBox(桥接网卡),VMware(桥接网卡)两台虚拟机(网段都在192.168.152.0/24࿰…...
从 Java 到 Kotlin:在现有项目中迁移的最佳实践!
全文目录: 开篇语 1. 为什么选择 Kotlin?1.1 Kotlin 与 Java 的兼容性1.2 Kotlin 的优势1.3 Kotlin 的挑战 2. Kotlin 迁移最佳实践2.1 渐进式迁移2.1.1 步骤一:将 Kotlin 集成到现有的构建工具中2.1.2 步骤二:逐步迁移2.1.3 步骤…...
