Python并发编程:揭开多线程与异步编程的神秘面纱

第一章:并发编程导论

1.1 并发与并行概念解析

1.1.1 并发性与并行性的区别

想象一下繁忙的厨房中多位厨师同时准备不同的菜肴——即使他们共享有限的空间和资源,也能协同工作,这就是并发性的一个生动比喻。并发性意味着多个任务在同一时间段内看似同时进行,但实际上可能交替执行。而在并行性中,多个任务真正意义上是在同一时刻由不同处理器或核心独立完成。例如,多台烤箱同时烹饪不同的菜品,每台烤箱都是一个独立的处理器,各自执行各自的烹饪任务。

1.1.2 并发编程的重要性及其挑战

在现代软件工程中,并发编程至关重要,因为它能够充分利用多核处理器的优势,有效提高系统吞吐量和响应速度。然而,它也带来了诸如竞态条件、死锁、活锁和资源争抢等问题。如同一场精心编排的芭蕾舞剧,若不妥善安排舞者们(即线程)的移动和动作(即状态变更),就可能导致舞台上的混乱甚至演出中断。

1.2 Python中的并发模型

1.2.1 全局解释器锁(GIL)的影响

全局解释器锁(Global Interpreter Lock, GIL)是Python并发编程绕不开的话题。如同独木桥上的守卫,GIL确保任何时候只有一个线程在执行Python字节码。尽管保证了内存安全,但也意味着在单个进程中,即便有多核CPU,也无法实现真正的并行计算。这对于CPU密集型任务来说,可能会导致性能瓶颈。

1.2.2 Python对多线程、多进程的支持

尽管受到GIL约束,Python依然提供了丰富的并发原语。对于多线程编程,可通过内置的threading模块创建和管理线程;而对于突破GIL限制,多进程编程则是一个可行的选择,multiprocessing模块为此提供了强大的支持。接下来我们将深入探索这两个领域,结合实例代码展示如何创建线程、解决并发问题以及在适当场合下使用多进程。例如,下面是一个简单的多线程实例:

import threadingdef worker(num):"""线程执行的任务"""print(f"Worker {num} is running.")# 创建并启动两个线程
threads = [threading.Thread(target=worker, args=(i,)) for i in range(2)]
for t in threads:t.start()
for t in threads:t.join()  # 确保所有线程执行完毕

这段代码展示了如何在Python中创建并启动两个线程来并发执行同一个函数。随着章节推进,我们将进一步讨论线程间的同步机制以及在不同场景下选择合适的并发策略。

第二章:Python多线程魔法阵

2.1 线程基础与线程生命周期

2.1.1 threading模块介绍

在Python的世界里,多线程犹如魔法师手中的魔杖,通过threading模块我们可以轻松地编织出并发执行的神奇景象。这个模块提供了创建、管理线程的基本结构,允许我们定义线程任务,进而实现任务的并发执行。线程就像一个个独立的工人,在同一个进程的工厂里各司其职,共同推进整体工作的进度。

2.1.2 创建与启动线程实例

想象一下,你正在经营一家咖啡厅,每位服务员就是一个线程,负责不同的订单任务。创建线程的过程就如同雇佣一位新服务员,为其分配特定的工作任务:

import threadingclass CoffeeOrderThread(threading.Thread):def __init__(self, order_id):super().__init__()self.order_id = order_iddef run(self):print(f"开始制作订单{self.order_id}的咖啡...")# 在此处模拟咖啡制作过程(比如耗时操作)time.sleep(2)print(f"订单{self.order_id}的咖啡已完成!")# 创建两个线程实例
order1 = CoffeeOrderThread(1)
order2 = CoffeeOrderThread(2)# 启动线程
order1.start()
order2.start()# 确保所有线程都完成工作
order1.join()
order2.join()
2.1.3 线程同步机制:锁、条件变量、信号量等

为了防止咖啡厅里的原料被同时取用造成混乱,我们需要引入同步机制。就好比给咖啡豆罐子加一把锁,只有拿到钥匙的服务员才能取用豆子:

import threadingcoffee_lock = threading.Lock()def prepare_coffee(order_id):with coffee_lock:print(f"开始为订单{order_id}磨咖啡豆...")# 磨豆子(同步操作)time.sleep(1)print(f"完成订单{order_id}的磨豆工作!")# 分别在两个线程中执行
threads = [threading.Thread(target=prepare_coffee, args=(i,)) for i in range(1, 3)]
for thread in threads:thread.start()
for thread in threads:thread.join()
2.1.4 经典多线程问题及解决方案
  • 死锁与饥饿问题
    死锁就像是咖啡厅里的服务员们都互相等待对方释放所需的资源而停滞不前。解决死锁的关键在于避免循环等待和资源抢占,可以通过设置超时、资源有序申请等方式预防。

示例:

lock1 = threading.Lock()
lock2 = threading.Lock()def deadlock_thread(id):if id == 1:lock1.acquire()print("线程1获得第一个锁")try:lock2.acquire(True, 2)  # 设置超时避免无限等待except threading.LockTimeout:print("线程1获取第二个锁超时,避免了死锁")else:print("线程1获得了两个锁,正常执行")elif id == 2:lock2.acquire()print("线程2获得第一个锁")try:lock1.acquire(True, 2)except threading.LockTimeout:print("线程2获取第二个锁超时,避免了死锁")else:print("线程2获得了两个锁,正常执行")# 创建并启动线程
thread1 = threading.Thread(target=deadlock_thread, args=(1,))
thread2 = threading.Thread(target=deadlock_thread, args=(2,))
thread1.start()
thread2.start()
  • 生产者消费者问题示例
    生产者消费者问题是多线程同步的经典案例,就像吧台服务员和烘焙师之间的协作。生产者(烘焙师)不断制作面包,消费者(服务员)则在面包做好时将其取出上桌。借助队列和条件变量可以完美解决这个问题。
import queue
import threadingbread_queue = queue.Queue(maxsize=5)
stop_event = threading.Event()def producer():while not stop_event.is_set():bread = make_bread()  # 制作面包bread_queue.put(bread)print("生产者制作了一块面包")def consumer():while not stop_event.is_set() or not bread_queue.empty():if not bread_queue.empty():bread = bread_queue.get()serve_customer(bread)  # 上桌面包print("消费者为顾客送上一块面包")def start_threads():producer_thread = threading.Thread(target=producer)consumer_thread = threading.Thread(target=consumer)producer_thread.start()consumer_thread.start()# 运行一段时间后停止time.sleep(5)stop_event.set()# 等待所有线程结束producer_thread.join()consumer_thread.join()start_threads()

2.2 Python多线程实践策略

2.2.1 I/O密集型任务中的多线程优化

在I/O密集型任务如网络请求或文件读写中,由于大量时间花费在等待外部响应而非CPU运算,多线程能够显著提高效率。即使受制于GIL,每个线程仍能在等待I/O操作时释放GIL,让其他线程有机会执行。

2.2.2 CPU密集型任务中的多线程局限性

对于纯CPU计算任务,由于GIL的存在,多线程在单个进程中并不能带来实质性的并行计算优势。这时,多进程或多进程与异步I/O的组合将是更好的选择。

2.2.3 使用concurrent.futures模块简化多线程编程

Python标准库中的concurrent.futures模块提供了高层级的异步接口,使得多线程编程变得更加简洁易用。通过ThreadPoolExecutor,我们可以方便地管理和调度一组线程,从而简化并发任务的组织和执行。

from concurrent.futures import ThreadPoolExecutorwith ThreadPoolExecutor(max_workers=5) as executor:future_to_url = {executor.submit(fetch_data, url): url for url in urls}for future in concurrent.futures.as_completed(future_to_url):url = future_to_url[future]try:data = future.result()except Exception as exc:print(f"获取 {url} 数据时发生错误: {exc}")else:process_data(data)

第三章:异步编程的奇妙世界

3.1 异步编程理念与事件驱动模型

3.1.1 单线程异步I/O概述

想象一个热闹的餐厅,一位服务员在单一的工作台上接待众多客人。虽然只有一人服务,但服务员并不会因为等待某个客人的菜单确认而闲下来,而是会在等待的同时去询问其他客人的需求,然后高效地来回穿梭于厨房与餐桌之间。这种高效的运作模式就是异步编程的一种直观体现。在计算机术语中,单线程异步I/O意味着即使在一个单独的线程中,也可以通过非阻塞式I/O操作和事件循环机制,使程序在等待I/O完成时继续处理其他任务,大大提高了系统的并发能力。

3.1.2 Python中的异步框架比较(asyncio, Twisted等)

在Python生态系统中,有两个突出的异步编程框架:asyncio 和 Twisted。asyncio 是 Python 3.4 版本起引入的标准库,以其简洁易用的 async/await 关键字和 EventLoop 构建的异步编程模型,迅速成为现代Python异步编程的主流工具。而Twisted作为历史悠久的异步框架,尤其擅长网络编程,提供了广泛的协议支持,尽管学习曲线稍陡峭,但在一些复杂的网络应用中仍然有着不可替代的地位。

3.2 Python asyncio模块详解

3.2.1 async/await关键字与协程基础

在asyncio的世界里,async关键字用于定义一个协程函数,它们像普通的函数一样可以包含任意Python语句,但是当遇到await表达式时会暂停执行,直到其后的异步操作完成。协程就好似接力赛中的运动员,当一个任务到达需要等待的环节时,它会把控制权交给下一个等待执行的协程。

import asyncioasync def fetch_data(url):response = await get_http_response(url)  # 假设get_http_response是异步HTTP请求函数return response.text()async def process_urls(urls):tasks = [fetch_data(url) for url in urls]results = await asyncio.gather(*tasks)for result in results:print(result)# 启动事件循环
loop = asyncio.get_event_loop()
try:loop.run_until_complete(process_urls(["http://example.com"]))
finally:loop.close()
3.2.2 Future、Task与EventLoop的核心组件
  • Future:代表未来某个时刻可能完成的结果,它是异步编程中的基本构造块,封装了异步操作的结果或者异常。

  • Task:是对Future的封装,增加了调度和取消功能,是EventLoop上运行的具体工作单元。

  • EventLoop:是整个异步编程的大脑,负责调度协程,监控Future的状态变化,以及处理定时器和其他异步资源。当Future完成时,EventLoop会触发适当的回调,从而推动协程的执行。

3.2.3 异步编程实战:HTTP请求、文件读写等案例
import aiohttp  # 异步HTTP客户端库async def fetch_async(url):async with aiohttp.ClientSession() as session:async with session.get(url) as response:return await response.text()async def main():html_content = await fetch_async('http://example.com')print(html_content)# 使用asyncio.run在主线程直接运行异步任务
asyncio.run(main())

3.3 异步编程的优势与应用场景

3.3.1 高并发场景下的性能提升

在高并发场景,如Web服务器、实时聊天应用或大规模数据抓取等,异步编程能够最大化利用单线程资源,减少不必要的上下文切换开销,使得单个线程可以处理更多的连接或请求,从而显著提升系统性能。

3.3.2 异步在实时数据流处理与Web服务器开发中的应用

在实时数据流处理中,例如股票交易实时报价系统、物联网传感器数据接收等,异步编程可以帮助程序及时响应各种事件,保证数据的实时性和准确性。而在Web服务器开发中,采用异步框架如Sanic、FastAPI配合

第四章:多进程编程与混合模式并发

4.1 multiprocessing模块介绍

4.1.1 进程间通信(IPC)机制

在Python中,multiprocessing模块是实现多进程编程的重要基石。相比于多线程,进程间不存在全局解释器锁(GIL)的问题,因此在CPU密集型任务上,多进程能充分利用多核CPU的优势。进程间通信(IPC, Inter-Process Communication)是多进程编程中的关键环节,通过管道(Pipe)、队列(Queue)、共享内存(Shared Memory)、信号量(Semaphore)等机制,进程间可以交换数据和同步执行状态。

例如,我们可以通过multiprocessing.Queue来在进程间传递消息:

from multiprocessing import Process, Queuedef worker(q):while True:item = q.get()  # 获取队列中的任务if item is None:break  # 若收到None,则退出循环process_item(item)q.task_done()  # 表示一项任务已完成def main():task_queue = Queue()# 创建多个工作者进程for _ in range(4):p = Process(target=worker, args=(task_queue,))p.start()# 将任务放入队列for task in tasks:task_queue.put(task)# 放入None来通知所有工作者进程结束for _ in range(4):task_queue.put(None)# 等待所有任务完成task_queue.join()# 关闭进程for p in processes:p.join()if __name__ == "__main__":main()
4.1.2 Pool类与进程池的使用

multiprocessing.Pool类为多进程编程提供了一个更便捷的方式,它可以创建一个进程池来管理一组工作进程。当你有大量任务需要执行时,进程池可以有效地分配和回收进程资源,提高执行效率。以下是一个使用进程池的例子:

from multiprocessing import Pooldef process_number(number):# 模拟耗时操作return number * numberif __name__ == "__main__":numbers = [1, 2, 3, 4, 5]with Pool(processes=3) as pool:# 使用map函数将任务分发到进程池squared_numbers = pool.map(process_number, numbers)print(squared_numbers)

4.2 多进程与多线程对比分析

4.2.1 GIL限制下为何选择多进程

全局解释器锁(GIL)是Python解释器为了数据安全而在多线程环境下引入的一个机制,但它限制了线程在多核CPU上的并行执行。因此,对于那些需要充分利用多核CPU性能的CPU密集型任务,尤其是不受GIL影响的计算密集型场景,多进程成为了理想的解决方案。多进程不仅规避了GIL的制约,还因进程间内存隔离的特点减少了潜在的数据竞争风险。

4.2.2 根据任务类型选择合适的并发模型

选择多进程还是多线程,通常取决于具体的应用场景和任务特点。对于I/O密集型任务,由于大部分时间都在等待外部I/O操作完成,多线程可以很好地利用这些空闲时间片,即便受限于GIL,也能在一定程度上提高系统响应速度。而对于CPU密集型任务,多进程能够更好地发挥多核CPU的优势,避免因GIL造成的性能瓶颈。

综合考虑资源消耗、通信开销和任务特性等因素,灵活运用多进程、多线程,甚至是结合异步编程,可以构建出既能满足性能需求又能保持代码简洁的高效并发解决方案。

第五章:异步I/O与协程的最佳实践

5.1 基于asyncio的高级特性与设计模式

5.1.1 异步上下文管理器与异步生成器

在Python的asyncio库中,异步上下文管理器(Async Context Manager)是协程编写过程中不可或缺的一部分,它帮助我们在进入和离开上下文时执行异步操作。例如,当我们需要异步打开和关闭文件时,可以利用async with语法优雅地管理资源:

import asyncio
import aiofilesasync def read_file(file_path):async with aiofiles.open(file_path, mode='r') as file:content = await file.read()return contentasync def main():content = await read_file('data.txt')print(content)# 运行主协程
asyncio.run(main())

此外,异步生成器(Asynchronous Generator)也是asyncio中的一大亮点。它允许我们在协程中使用yield关键字,这样就能逐段生成或消费数据,非常适合处理大数据流或连续的异步操作:

async def async_generator_example():for i in range(10):await asyncio.sleep(1)  # 模拟异步延迟操作yield iasync def consume_generator(gen):async for value in gen:print(f"Received value: {value}")async def main():generator = async_generator_example()await consume_generator(generator)asyncio.run(main())
5.1.2 使用协程进行复杂流程控制

在复杂的异步场景中,协程可以嵌套使用,结合asyncio.create_taskasyncio.waitasyncio.gather等函数,形成层次丰富、逻辑清晰的异步流程。例如,我们可以用协程同时发起多个HTTP请求,并等待所有请求完成:

import asyncio
import aiohttpasync def fetch_page(url):async with aiohttp.ClientSession() as session:async with session.get(url) as response:return await response.text()async def fetch_multiple_pages(urls):tasks = [asyncio.create_task(fetch_page(url)) for url in urls]responses = await asyncio.gather(*tasks)return responsesasync def main():urls = ['https://example1.com', 'https://example2.com', 'https://example3.com']page_contents = await fetch_multiple_pages(urls)for idx, content in enumerate(page_contents):print(f"Response from {urls[idx]}: {content[:100]}...")asyncio.run(main())

5.2 实战项目:构建高性能的并发服务

5.2.1 异步爬虫案例分析

设想一个异步爬虫项目,利用asyncio和aiohttp,我们可以并发地抓取多个网页的内容:

import asyncio
import aiohttp
from bs4 import BeautifulSoupasync def fetch_and_parse(url):async with aiohttp.ClientSession() as session:async with session.get(url) as response:text = await response.text()soup = BeautifulSoup(text, 'html.parser')title = soup.find('title').textreturn titleasync def crawl_websites(urls):titles = []async with aiohttp.ClientSession() as session:tasks = [asyncio.create_task(fetch_and_parse(url)) for url in urls]for response in await asyncio.gather(*tasks):titles.append(response)return titlesasync def main():urls = ['https://www.example1.com','https://www.example2.com','https://www.example3.com',]titles = await crawl_websites(urls)for title in titles:print(title)asyncio.run(main())
5.2.2 使用异步编程优化数据库操作

在数据库操作中,特别是涉及大量IO操作时,异步编程同样能大幅提升性能。例如,使用aiomysql或asyncpg库,我们可以异步地执行多个数据库查询:

import asyncio
import aiomysqlasync def fetch_records(query, params):conn = await aiomysql.connect(host='localhost', user='user', password='pass', db='test_db')async with conn.cursor() as cur:await cur.execute(query, params)records = await cur.fetchall()conn.close()return recordsasync def main():queries = [("SELECT * FROM table1 WHERE condition1", params1),("SELECT * FROM table2 WHERE condition2", params2)]tasks = [asyncio.create_task(fetch_records(query, params)) for query, params in queries]all_records = await asyncio.gather(*tasks)# 对结果进行合并或处理...asyncio.run(main())

通过上述例子,我们可以看到异步编程在处理I/O密集型任务时展现出的强大威力,它能让我们的并发服务更加高效、响应更快,充分挖掘硬件潜力,从而满足实际业务中对于高并发和实时性处理的需求。

第六章:并发编程的未来展望与实践指南

6.1 并发编程的未来趋势与技术发展

随着计算技术的进步和多核处理器的普及,我们正迎来一个并发编程的黄金时代。未来的并发编程将更加注重简化开发者的工作流程,提供更高层次的抽象和工具,同时保证程序的性能和安全性。例如,随着异步编程语言特性的不断完善,如Python中的async/await语法,开发者将能够以更直观和简洁的方式编写并发代码。此外,云计算和容器化技术的发展也将推动并发编程模式的创新,如通过微服务架构和Kubernetes等容器编排工具,实现更灵活的资源管理和服务部署。

6.2 实践指南:构建高效并发应用的策略

在构建高效的并发应用时,开发者需要综合考虑任务的性质、系统资源和预期的性能目标。对于I/O密集型任务,多线程和异步编程是提升效率的有效手段;而对于CPU密集型任务,多进程和分布式计算可能是更好的选择。此外,合理利用缓存和消息队列等中间件,可以减轻数据库压力,提高数据处理速度。开发者还应关注并发编程中的错误处理和异常管理,确保应用的稳定性和可靠性。

6.3 持续学习与实践:提升并发编程技能的途径

并发编程是一个不断发展的领域,要求开发者持续学习最新的技术和最佳实践。参与开源项目、阅读技术博客和论坛、参加技术会议和研讨会,都是获取新知识和交流经验的好途径。同时,通过实际项目中的问题解决和性能优化,可以不断提升自己的并发编程技能。

在这里插入图片描述


关注gzh不灵兔,Python学习不迷路,关注后后台私信,可进wx交流群,进群暗号【人生苦短】~~~

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

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

相关文章

【哈希】Leetcode 面试题 01.02. 判定是否互为字符重排

题目讲解 面试题 01.02. 判定是否互为字符重排 算法讲解 直观的想法:我们找到一个字符串的全排列,然后对比当前的排列是否等于另一个字符串。如果两个字符串如果互为排列,所以我们知道两个字符串对应的字符出现的个数相同,那么…

常用图像加密技术-流密码异或加密

异或加密是最常用的一种加密方式,广泛的适用于图像处理领域。这种加密方式依据加密密钥生成伪随机序列与图像的像素值进行异或操作,使得原像素值发生变化,进而使得图像内容发生变化,达到保护图像内容的目的。 该加密方法是以图像…

Aiseesoft Blu-ray Player for Mac:蓝光播放器

Aiseesoft Blu-ray Player for Mac是一款功能强大且易于使用的蓝光播放器,专为Mac用户打造。它以其卓越的性能和简洁的操作界面,为用户带来了全新的高清蓝光播放体验。 Aiseesoft Blu-ray Player for Mac v6.6.50激活版下载 这款软件支持播放任何高质量的…

【Leetcode每日一题】 动态规划 - 简单多状态 dp 问题 - 打家劫舍 II(难度⭐⭐)(67)

1. 题目解析 题目链接:213. 打家劫舍 II 这个问题的理解其实相当简单,只需看一下示例,基本就能明白其含义了。 2.算法原理 这个问题是经典的“打家劫舍”问题的变种,原问题是在单排房屋中进行偷窃,而这个问题则是在…

机器学习:基于Sklearn、XGBoost框架,使用XGBClassifier、支持向量分类器和决策树分类器预测乳腺癌是良性还是恶性

前言 系列专栏:机器学习:高级应用与实践【项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目,每个项目都处理一组不同的问题,包括监督和无监督学习、分类、回归和聚类,而且涉及创建深度学…

数据挖掘实验一

一、实验环境及背景 使用软件: Anaconda3 Jupyter Notebook 实验内容: 1.使用Tushare或者其他手段获取任意两支股票近三个月的交易数据。做出收盘价的变动图像。2.使用Pandas_datareader获取世界银行数据库中美国(USA)、瑞典&…

Linux-管道通信

1. 管道概念 管道,是进程间通信的一种方式,在Linux命令中“ | ”就是一种管道,它可以,连接前一条命令,和后一条命令,把前面命令处理完的内容交给后面,例如 cat filename | grep hello …

IDEA 中的奇技淫巧

IDEA 中的奇技淫巧 书签 在使用ctrlalt方向键跳转时,或者追踪代码时,经常遇到的情况是层级太多,找不到代码的初始位置,入口。可以通过书签的形式去打上一个标记,后续可以直接跳转到书签位置。 标记书签:c…

C# GetField 方法应用实例

目录 关于 C# Type 类 GetField 方法应用 应用举例 心理CT设计题 类设计 DPCT类实现代码 小结 关于 C# Type 类 Type表示类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型。调用 t…

新媒体运营-----短视频运营-----PR视频剪辑----视频调色

新媒体运营-----短视频运营-----PR视频剪辑-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/138079659 文章目录 1. Lumetri调色,明暗对比度2. Lumetri调色,创意与矢量示波器2.1 创意2.2 矢量示波器 3. L…

前端开发攻略---用原生JS在网页中也能实现语音识别

1、语音识别的过程 语音识别涉及三个过程:首先,需要设备的麦克风接收这段语音;其次,语音识别服务器会根据一系列语法 (基本上,语法是你希望在具体的应用中能够识别出来的词汇) 来检查这段语音;最后&#xf…

纯js对比excel小工具

如何使用JavaScript和xlsx.js实现Excel文件对比:实战指南 在日常办公或数据分析工作中,我们经常需要比较两个Excel文件中的数据差异。手动对比不仅耗时费力,还容易出错。本文将带你通过一个简单的网页应用,利用JavaScript和开源库…

【极速前进】20240422:预训练RHO-1、合成数据CodecLM、网页到HTML数据集、MLLM消融实验MM1、Branch-Train-Mix

一、RHO-1:不是所有的token都是必须的 论文地址:https://arxiv.org/pdf/2404.07965.pdf 1. 不是所有token均相等:token损失值的训练动态。 ​ 使用来自OpenWebMath的15B token来持续预训练Tinyllama-1B,每1B token保存一个che…

GPT学术优化推荐(gpt_academic )

GPT学术优化 (GPT Academic):支持一键润色、一键中英互译、一键代码解释、chat分析报告生成、PDF论文全文翻译功能、互联网信息聚合GPT等等 ChatGPT/GLM提供图形交互界面,特别优化论文阅读/润色/写作体验,模块化设计,支持自定义快捷按钮&…

[iOS]CocoaPods安装和使用

1.了解brew、rvm、ruby、gem、cocaspods之间的关系 在 macOS 环境中,Brew、RVM、Ruby、Gem 和 CocoaPods 之间存在以下关系: Homebrew (Brew):Homebrew 是 macOS 上的包管理器,用于安装和管理各种开源软件包。它使您能够轻松地从…

基于SpringBoot+Vue校园竞赛管理系统的设计与实现

项目介绍: 传统信息的管理大部分依赖于管理人员的手工登记与管理,然而,随着近些年信息技术的迅猛发展,让许多比较老套的信息管理模式进行了更新迭代,竞赛信息因为其管理内容繁杂,管理数量繁多导致手工进行…

【AIGC调研系列】Sora级别的国产视频大模型-Vidu

Vidu能够达到Sora级别的标准。Vidu被多个来源认为是国内首个Sora级别的视频大模型[2][3][4]。它采用了团队原创的Diffusion与Transformer融合的架构U-ViT,能够生成长达16秒、分辨率高达1080P的高清视频内容[1][6]。此外,Vidu的一致性、运动幅度都达到了S…

HEVC/H.265视频编解码学习笔记–框架及块划分关系

前言 由于本人在学习视频的过程中,觉得分块单元太多搞不清楚其关系,因此本文着重记录这些分块单元的概念以及关联。 一、框架 视频为一帧一帧的图像,其编码的主要核心是压缩空间以及时间上的冗余。因此,视频编码有帧内预测和帧间…

使用docker搭建GitLab个人开发项目私服

一、安装docker 1.更新系统 dnf update # 最后出现这个标识就说明更新系统成功 Complete!2.添加docker源 dnf config-manager --add-repohttps://download.docker.com/linux/centos/docker-ce.repo # 最后出现这个标识就说明添加成功 Adding repo from: https://download.…

uniapp分包,以及通过uni-simple-router进行分包

先说一下uniapp的直接分包方式,很简单: 配置分包信息 打开manifest.json源码视图,添加 “optimization”:{“subPackages”:true} 开启分包优化 我们在根目录下创建一个pagesA文件夹,用来放置需要分包的页面 然后配置路由 运行到…