Python异步编程-asyncio详解

news2024/9/21 19:37:53

目录

  • asyncio简介
    • 示例
    • 什么是 asyncio?
    • 适用场景
    • API
  • asyncio的使用
    • 可等待对象
      • 什么是可等待对象?
      • 协程对象
      • 任务对象
      • Future对象
    • 协程
      • 什么是协程?
      • 基本使用
      • 运行协程
    • Task
      • 什么是 Task?
      • 创建 Task
      • 取消 Task
      • Task 异常获取
      • Task 回调
    • TaskGroup
      • 什么是 TaskGroup?
      • 为什么使用 TaskGroup?
      • 创建任务
      • 异常处理
      • 同步任务完成

asyncio简介

示例

首先,我们来看一个简单的Hello World示例代码:

import asyncio

async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')

asyncio.run(main())


""" 
输出:
Hello ...
... World!
"""

这个例子展示了如何使用 asyncio 库来编写并发代码。通过 asyncawait 语法,我们可以让 Python 程序在执行IO操作(如计算、文件读写、网络请求等)时实现在其他任务间高效切换,从而提升程序性能。

什么是 asyncio?

asyncio 是一个用于编写并发代码的Python库,允许我们利用 asyncawait 关键字进行异步编程。作为多个Python异步框架的基础,asyncio 提供了诸如高性能网络和Web服务器、数据库连接库以及分布式任务队列等功能。

适用场景

asyncio 非常适合用于 IO密集型和高层次结构化网络代码处理。其高效的异步IO处理方式,使其在需要大量网络通信和异步操作的场景中表现优异。

API

高级API用于:

  • 并发运行Python协程,完全控制它们的执行;
  • 执行网络IO和进程间通信(IPC);
  • 控制子进程;
  • 通过队列分发任务;
  • 同步并发代码。

低级API用于(库和框架开发人):

  • 创建和管理事件循环,提供异步API实现网络通信、运行子进程、处理OS信号等;
  • 使用 transports 实现高效率协议;
  • 用异步语法桥接基于回调的库和代码。

asyncio的使用

可等待对象

什么是可等待对象?

简单来说,可等待对象是可以在await表达式中使用的对象。它们可以暂停异步函数的执行,等待某个操作完成后再恢复执行。Python中的可等待对象主要包括三种类型:

  1. 协程对象(coroutine objects)
  2. 任务对象(tasks)
  3. Future对象(futures)

协程对象

协程函数是定义时使用async def语句的函数。当调用协程函数时,会返回一个协程对象。这些对象必须在事件循环中运行,可以直接被await

import asyncio

async def main():
    await asyncio.sleep(1)
    print("Hello, world!")

# 运行协程
asyncio.run(main())

在上面的示例中,main()是一个协程函数,调用它返回一个协程对象。asyncio.run(main())将运行事件循环并执行协程。

任务对象

任务对象是对协程对象的进一步封装,被用来“并行的”调度协程,它们会安排协程在事件循环中执行,并可以跟踪协程的状态和结果。可以通过asyncio.create_task函数创建任务,当一个协程通过 asyncio.create_task() 等函数被封装为一个任务,该协程会被自动调度执行。

import asyncio

async def say_hello():
    await asyncio.sleep(1)
    print("Hello!")

async def main():
    task = asyncio.create_task(say_hello())
    await task

asyncio.run(main())

在这个示例中,我们使用asyncio.create_task创建了一个任务对象,该对象随后被await,这意味着程序将等待任务完成。

Future对象

Future对象表示一个将来可能会有结果的操作,他们主要是用于低级别的异步编程。通常情况下,没有必要在应用层级的代码中创建 Future 对象。开发者更多使用高层次的抽象如任务对象,但了解Future对象仍然很有价值。

import asyncio

async def set_future_value(fut):
    await asyncio.sleep(1)
    fut.set_result("Finished!")

async def main():
    fut = asyncio.Future()
    await asyncio.create_task(set_future_value(fut))
    result = await fut
    print(result)

asyncio.run(main())

在这个示例中,通过asyncio.Future()创建了一个Future对象,并在一个协程中使用set_result方法设置了其结果。

协程

什么是协程?

协程(Coroutine)是一种比线程更轻量级的“并发”方式。它允许程序在同一个线程里“并行”地执行多个任务。这里“并行”并不是指真正的并行执行,而是协程可以在任务之间快速切换,从而让这些任务看起来像是同时进行的。

你可以把协程想象成一个大办公室里的一名员工,这名员工需要完成一些任务,比如接电话、发邮件、写报告。这些任务可能需要等一段时间才能完成,比如等电话的对方回复,等邮件发送成功,或者等等数据。但是在等待的时间里,这名员工不会闲着,他会继续去做别的任务。

  • 线程就像是一个员工每做一个任务他就需要一个独立的办公桌。线程是重量级的,需要更多资源,启动和管理也更复杂。
  • 协程就像是一个员工在同一个办公桌上同时处理多个任务,快速切换。协程是轻量级的,消耗的资源很少,启动和管理也比较简单。

基本使用

  • 定义协程函数:使用 async def 关键字定义一个协程函数。
async def my_coroutine():
    pass
  • 运行协程:可以使用 await 关键词等待另一个协程完成,或使用 asyncio.run() 来运行最顶层的入口点协程。
import asyncio


async def my_coroutine():
    print("这是使用await运行的协程")


async def main():
    print("使用asyncio.run运行协程开始")
    await my_coroutine()
    print("使用asyncio.run运行协程结束")

asyncio.run(main())


"""
输出:
使用asyncio.run运行协程开始
这是使用await运行的协程
使用asyncio.run运行协程结束
"""

注意:简单地调用一个协程并不会使其被调度执行

# python console 中运行
async def my_coroutine():
    print("my coroutine")
    
my_coroutine()
<coroutine object my_coroutine at 0x104519f50>

运行协程

  • 使用asyncio.run() 函数用来运行最顶层的入口点 “main()” 函数 (见上面的示例)

  • 使用await执行(以下代码段会在等待3秒后打印 "1号协程"结束时间,然后再次等待5秒后打印 "2号协程"完成时间)

    import asyncio
    import time
    
    
    async def my_coroutine(name, delay):
        await asyncio.sleep(delay)  # 模拟I/O操作
        print(f"{name}完成时间:{time.time()}")
    
    
    async def main():
        start_time = time.time()
        print(f"开始时间 {start_time}")
    
        await my_coroutine("1号协程", 3)
        await my_coroutine("2号协程", 5)
    
        end_time = time.time()
        print(f"结束时间 {end_time}")
        print(f"耗时{end_time - start_time:.2f}秒")
    
    
    asyncio.run(main())
    
    """
    输出:
    开始时间 1726210238.44529
    1号协程完成时间:1726210241.446931
    2号协程完成时间:1726210246.4494321
    结束时间 1726210246.449468
    耗时8.00秒
    """
    
  • asyncio.create_task() 函数用来并发运行作为 asyncio 任务的多个协程。(修改以上示例,并发运行两个协程)

    import asyncio
    import time
    
    
    async def my_coroutine(name, delay):
        await asyncio.sleep(delay)  # 模拟I/O操作
        print(f"{name}完成时间:{time.time()}")
    
    
    async def main():
        start_time = time.time()
        print(f"开始时间 {start_time}")
        task1 = asyncio.create_task(my_coroutine("1号协程", 3))
        task2 = asyncio.create_task(my_coroutine("2号协程", 5))
        await task1
        await task2
        end_time = time.time()
        print(f"结束时间 {end_time}")
        print(f"耗时{end_time - start_time:.2f}秒")
    
    
    asyncio.run(main())
    
    
    """
    输出:
    开始时间 1726210659.84198
    1号协程完成时间:1726210662.843559
    2号协程完成时间:1726210664.842549
    结束时间 1726210664.84267
    耗时5.00秒
    """
    # 可以明显看出总耗时比之前明显快了3秒,1和2之间的时间间隔也变成了2秒
    
  • asyncio.TaskGroup 类提供了 create_task() 的替代。 使用此 API,之前的例子可以改为

    async def main():
        start_time = time.time()
        print(f"开始时间 {start_time}")
    
        async with asyncio.TaskGroup() as tg:
            task1 = tg.create_task(my_coroutine("1号协程", 3))
            task2 = tg.create_task(my_coroutine("2号协程", 5))
    
        end_time = time.time()
        print(f"结束时间 {end_time}")
        print(f"耗时{end_time - start_time:.2f}秒")
    

Task

什么是 Task?

在 asyncio 中,Task 是对协程进行调度管理的对象。Task 实际上是 asyncio 事件循环的一个抽象概念,通过 Task 我们可以控制协程(coroutine)的执行,允许它们并发运行。在底层,Task 使用事件循环调度多个协程,使得它们似乎是同时运行的。

asyncio.Task 对象可以被看作是 Future 的一种特化,用于运行 Python 协程。它们被设计用来在事件循环中调度和运行协程。
Task对象是非线程安全的,意味着它们主要用于单线程的 asyncio 事件循环。

创建 Task

  • 使用 asyncio.create_task() 方法,
    asyncio.create_task() 是创建 Task 的最常见方法,它会立即调度协程的运行并返回一个 Task 对象:

    import asyncio
    import time
    
    
    async def my_coroutine():
        print(f"协程开始时间 {time.strftime('%X')}")
        await asyncio.sleep(2)
        print(f"协程结束时间 {time.strftime('%X')}")
    
    
    async def main():
        print(f"主协程开始时间:{time.strftime('%X')}")
    
        # 创建一个 Task
        task = asyncio.create_task(my_coroutine())
    
        print(f"任务创建时间:{time.strftime('%X')}")
    
        # 稍微等待一下,但不会 await Task
        await asyncio.sleep(5)
    
        print(f"延时结束,开始等待任务:{time.strftime('%X')}")
    
        # 现在等待 Task 完成
        await task
    
        print(f"主协程结束时间:{time.strftime('%X')}")
    
    
    # 运行主协程
    asyncio.run(main())
    
    """
    输出:
    主协程开始时间:17:45:30
    任务创建时间:17:45:30
    协程开始时间 17:45:30
    协程结束时间 17:45:32
    延时结束,开始等待任务:17:45:35
    主协程结束时间:17:45:35
    """
    

    在上面的示例中,asyncio.create_task(my_coroutine()) 创建了一个 Task,它会立即开始运行 my_coroutine 协程,即使我还并没有执行await。

  • 使用 loop.create_task() 方法

    我们还可以通过获取事件循环,然后调用它的 create_task 方法来创建任务:

    import asyncio
    import time
    
    
    async def my_coroutine():
        print(f"协程开始时间 {time.strftime('%X')}")
        await asyncio.sleep(2)
        print(f"协程结束时间 {time.strftime('%X')}")
    
    
    async def main():
        print(f"主协程开始时间:{time.strftime('%X')}")
    
        # 创建一个 Task
        loop = asyncio.get_running_loop()
        task = loop.create_task(my_coroutine())
    
        print(f"任务创建时间:{time.strftime('%X')}")
    
        # 稍微等待一下,但不会 await Task
        await asyncio.sleep(5)
    
        print(f"延时结束,开始等待任务:{time.strftime('%X')}")
    
        # 现在等待 Task 完成
        await task
    
        print(f"主协程结束时间:{time.strftime('%X')}")
    
    
    # 运行主协程
    asyncio.run(main())
    
    """
    输出:
    主协程开始时间:17:50:03
    任务创建时间:17:50:03
    协程开始时间 17:50:03
    协程结束时间 17:50:05
    延时结束,开始等待任务:17:50:08
    主协程结束时间:17:50:08
    """
    

    在上面的示例中,使用asyncio.get_running_loop() 获取当前正在运行的事件循环,loop.create_task(my_coroutine()) 使用事件循环的 create_task 方法创建并调度一个协程任务。
    asyncio.create_task()loop.create_task()的不同之处:

    • asyncio.create_task():是一个便捷方法,直接通过当前的默认事件循环创建任务
    • loop.create_task():需要明确提供事件循环,适用于更复杂或特定需求的场景,比如管理多个事件循环。
  • 使用 asyncio.ensure_future()
    虽然不如前两种方法常用,但 asyncio.ensure_future 也可以用来创建 Task。它可以接受协程或 Future 对象,并确保返回一个 Task:

    import asyncio
    import time
    
    
    async def my_coroutine():
        print(f"协程开始时间 {time.strftime('%X')}")
        await asyncio.sleep(2)
        print(f"协程结束时间 {time.strftime('%X')}")
    
    
    async def main():
        print(f"主协程开始时间:{time.strftime('%X')}")
    
        # 创建一个 Task
        task = asyncio.ensure_future(my_coroutine())
    
        print(f"任务创建时间:{time.strftime('%X')}")
    
        # 稍微等待一下,但不会 await Task
        await asyncio.sleep(5)
    
        print(f"延时结束,开始等待任务:{time.strftime('%X')}")
    
        # 现在等待 Task 完成
        await task
    
        print(f"主协程结束时间:{time.strftime('%X')}")
    
    
    # 运行主协程
    asyncio.run(main())
    
    """
    输出:
    主协程开始时间:18:00:54
    任务创建时间:18:00:54
    协程开始时间 18:00:54
    协程结束时间 18:00:56
    延时结束,开始等待任务:18:00:59
    主协程结束时间:18:00:59
    """
    

    asyncio.ensure_future() 是一个功能强大的函数,常用于将一个协程转换为一个 Future 对象。
    它在处理异步任务时提供了更多的灵活性,特别是在需要将协程包装为 Future 时。
    asyncio.create_task()asyncio.ensure_future() 的不同之处:

    • asyncio.create_task():专门用于将协程转换为 Task,只能处理协程对象。
    • asyncio.ensure_future():可以处理协程对象和 Future 对象,更加通用,适用于更多场景。

取消 Task

asyncio 中,当一个 Task 对象的 cancel() 方法被调用时,它会请求取消该任务。具体步骤如下:

  1. 标记任务为取消状态:调用 cancel() 方法后,任务会被标记为取消状态。
  2. 抛出 CancelledError 异常:再次调度这个任务时,它会在等待的位置抛出一个 asyncio.CancelledError 异常。
  3. 任务处理异常:协程内部可以捕获这个异常,进行相应的清理操作。
import asyncio


async def cancellable_task():
    try:
        print("Task 启动")
        await asyncio.sleep(10)  # 长时间任务
        print("Task 完成")
    except asyncio.CancelledError:
        print("Task 被取消")
        raise  # 重新抛出err,以便外部可以检测到任务已被取消


async def main():
    task = asyncio.create_task(cancellable_task())
    await asyncio.sleep(2)  # 等待一段时间
    task.cancel()  # 请求取消任务

    try:
        await task
    except asyncio.CancelledError:
        print("主协程: Task 被取消")


asyncio.run(main())

"""
输出:
Task 启动
Task 被取消
主协程: Task 被取消
"""

在这个例子中,main() 协程启动了一个长时间运行的任务 cancellable_task() 并在2秒后请求取消它。

Task 异常获取

asyncio 中,Task 对象继承了 Future 对象的许多方法和属性,其中包括 exception() 方法。exception() 用于获取任务在执行过程中抛出的异常。如果任务完成且没有异常发生,exception() 返回 None。如果任务还未完成,调用 exception() 将会引发 asyncio.InvalidStateError 异常。因此,通常我们需要在任务完成之后调用 exception() 方法。

import asyncio


async def my_task():
    await asyncio.sleep(1)
    raise ValueError("任务执行出错")


async def main():
    task = asyncio.create_task(my_task())

    try:
        await task
    except Exception as e:
        print(f"主协程中捕获异常: {e}")

    # 现在任务已经完成,可以检查异常
    if task.exception():
        print(f"任务结束通过exception方法检查异常: {task.exception()}")


asyncio.run(main())

"""
输出:
主协程中捕获异常: 任务执行出错
任务结束通过exception方法检查异常: 任务执行出错
"""

在这个示例中,my_task() 会抛出一个 ValueError 异常。我们在主协程 main() 中捕获该异常,同时也通过 exception() 方法再次获取并打印异常。

Task 回调

add_done_callback() 方法是 asyncio 提供的一个强大的工具,允许我们在任务完成后执行特定的回调函数。回调函数帮助我们更有效地管理任务的生命周期,处理结果和异常,并执行一些后续操作。

import asyncio


async def my_task():
    await asyncio.sleep(1)  # 模拟一些异步操作
    return "一键三连"


def task_done_callback(future):
    print(f"回调-任务已完成,结果: {future.result()}")


async def main():
    task = asyncio.create_task(my_task())
    task.add_done_callback(task_done_callback)
    await task  # 等待任务完成


asyncio.run(main())


"""
输出:
回调-任务已完成,结果: 一键三连
"""

在这个例子中,task_done_callback 回调函数会在 my_task 任务完成后被调用,并打印任务的结果。

import asyncio


async def failing_task():
    await asyncio.sleep(1)
    raise ValueError("任务出现了奇怪的错误")


def task_done_callback(future):
    if future.exception():
        print(f"回调-任务失败,异常: {future.exception()}")
    else:
        print(f"回调-任务完成,结果: {future.result()}")


async def main():
    task = asyncio.create_task(failing_task())
    task.add_done_callback(task_done_callback)
    try:
        await task
    except Exception as e:
        print(f"主协程捕获异常: {e}")


asyncio.run(main())


"""
输出:
回调-任务失败,异常: 任务出现了奇怪的错误
主协程捕获异常: 任务出现了奇怪的错误
"""

在这个示例中,当 failing_task 抛出异常时,task_done_callback 会检测并打印异常,而主协程也会捕获并处理该异常。

TaskGroup

什么是 TaskGroup?

TaskGroup 是 Python 3.11 中新增的 asyncio 组件。它提供了一种更简洁、更安全的方式来管理多个并发任务。TaskGroup 是一个上下文管理器,当与 async with 语句一起使用时,它允许我们在一个块内启动多个任务,并确保这些任务在上下文管理器退出时正确清理。

为什么使用 TaskGroup?

  1. 更简洁的语法:在没有 TaskGroup 之前,管理多个任务通常需要手动创建每个任务并在最后通过 await 语句等待所有任务完成。TaskGroup 简化了这一过程。
  2. 更好的错误处理:由于 TaskGroup 是一个上下文管理器,它更容易管理任务中的异常情况。
  3. 更清晰的结构:代码的可读性和结构性得到了显著提升。

创建任务

TaskGroup 中创建任务使用 create_task 方法。每个任务会立即调度,并在 TaskGroup 的管理范围内运行。

import asyncio
import time


async def task(n):
    print(f"任务 {n} 启动 {time.strftime('%X')}")
    await asyncio.sleep(2)
    print(f"任务 {n} 结束 {time.strftime('%X')}")


async def main():
    async with asyncio.TaskGroup() as tg:
        tg.create_task(task(1))
        tg.create_task(task(2))
        tg.create_task(task(3))


asyncio.run(main())


"""
输出:
任务 1 启动 17:08:18
任务 2 启动 17:08:18
任务 3 启动 17:08:18
任务 1 结束 17:08:20
任务 2 结束 17:08:20
任务 3 结束 17:08:20
"""

在这个示例中,我们通过 async with 语句创建了一个 TaskGroup,并使用 create_task 方法启动了三个并行运行的任务 task(n),这三个任务立即调度,并在 TaskGroup 的管理范围内运行。当所有任务完成时,TaskGroup 会自动进行清理。

异常处理

TaskGroup 中的任务引发异常时,异常会在退出 async with 块时处理。如果多个任务引发异常,TaskGroup 会聚合这些异常,并引发一个 ExceptionGroup 异常。

import asyncio


async def error_task():
    raise RuntimeError("一些奇怪的错误")


async def main():
    try:
        async with asyncio.TaskGroup() as tg:
            tg.create_task(error_task())
            tg.create_task(error_task())
            tg.create_task(error_task())
    except ExceptionGroup as e:
        print("任务组捕获异常: ", e)


asyncio.run(main())


"""
输出:
任务组捕获异常:  unhandled errors in a TaskGroup (3 sub-exceptions)
"""

在使用 asyncio.TaskGroup 时,如果多个任务引发异常,异常会被聚合成一个 ExceptionGroup 异常,并在 TaskGroup 上下文管理器退出时被捕获和处理。然而,默认情况下,ExceptionGroup 只提供较为简略的信息。要看到具体的子异常信息,我们需要更详细地打印 ExceptionGroup 对象。

import asyncio


async def error_task():
    raise RuntimeError("一些奇怪的错误")


async def main():
    try:
        async with asyncio.TaskGroup() as tg:
            tg.create_task(error_task())
            tg.create_task(error_task())
            tg.create_task(error_task())
    except ExceptionGroup as e:
        print("任务组捕获异常:")
        for sub_exception in e.exceptions:
            print(f"子异常: {sub_exception}")


asyncio.run(main())


"""
输出:
任务组捕获异常:
子异常: 一些奇怪的错误
子异常: 一些奇怪的错误
子异常: 一些奇怪的错误
"""

在上面的示例中,我们在捕获 ExceptionGroup 异常后,迭代其 exceptions 属性,逐个打印出子异常的信息。这样可以更全面了解 ExceptionGroup 中包含的所有异常。

同步任务完成

TaskGroup 保证所有任务在同一个上下文管理器范围内完成。如果某个任务需要较长时间完成,其他任务会等待它。

import asyncio


async def long_task():
    await asyncio.sleep(5)
    print("长任务完成")


async def short_task():
    await asyncio.sleep(1)
    print("短任务完成")


async def main():
    async with asyncio.TaskGroup() as tg:
        tg.create_task(long_task())
        tg.create_task(short_task())
    print("所有任务完成")


asyncio.run(main())

"""
输出:
短任务完成
长任务完成
所有任务完成
"""

上面的示例展示了如何使用 asyncio.TaskGroup 同时管理多个异步任务,其中短任务先完成并输出结果,长任务随后完成,最终确保所有任务结束后输出 “所有任务完成”。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IDEA中实现springboot热部署

IDEA中实现springboot热部署 热部署: 每一次修改代码后会自动更新&#xff0c;无需每次重启 依赖(pom.xml) 修改后记得Reload一下 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><…

微信小程序IOS真机调试-onPullDownRefresh和onReachBottom不生效

切换真机调试2.0版本 勾选JS编译成ES5 如果使用了 uniapp&#xff0c;这里也需要勾选 重新启动

系统架构笔记-3-信息系统基础知识

知识要点 结构化方法&#xff1a;结构是指系统内各个组成要素之间的相互联系、相互作用的框架。结构化方法也称为生命周期法&#xff0c;是一种传统的信息系统开发方法&#xff0c;由结构化分析、结构化设计、结构化程序设计三部分有机组合而成&#xff0c;精髓是自顶向下、逐…

Java笔试面试题AI答之设计模式(2)

文章目录 6. 什么是单例模式&#xff0c;以及他解决的问题&#xff0c;应用的环境 &#xff1f;解决的问题应用的环境实现方式 7. 什么是工厂模式&#xff0c;以及他解决的问题&#xff0c;应用的环境 &#xff1f;工厂模式简述工厂模式解决的问题工厂模式的应用环境工厂模式的…

高算力芯片的发展

最近参与了2024年北京AI芯片峰会&#xff0c;虽然是讲AI芯片&#xff0c;但因为目前算力主要讲的是智能算力&#xff0c;所以&#xff0c;针对高算力芯片的发展趋势有重点的讲解。之前没有很系统关注这块&#xff0c;这次算是做了全面了解。下面&#xff0c;借用峰会的一些内容…

九章云极DataCanvas公司荣获2024年服贸会“科技创新服务示范案例”

9月15日&#xff0c;2024年中国国际服务贸易交易会&#xff08;服贸会&#xff09;示范案例交流会暨颁奖典礼在北京国家会议中心举行&#xff0c;九章云极DataCanvas 公司自研的DataCanvas Alaya NeW智算操作系统凭借卓越的AI创新实力、前瞻性的市场布局以及突破性的技术革新成…

uniapp中使用echarts 完整步骤,包括报错以及解决方案

在我们日常可能会有小程序中要使用echarts&#xff0c;我今天总结了一下整个引入的步骤 首先echarts - DCloud 插件市场在插件市场里面导入进项目&#xff0c;我这边用的是vue3的以及主要开发小程序&#xff0c;就直接放我的案例了 按照上面的步骤&#xff0c;在样式部分这样…

javaseday28 IO

IO流 IO流;存储和读取数据的解决方案。 纯文本文件&#xff1a;Windows自带的记事本打开能读懂的文件&#xff0c;word和Excel不是纯文本文件&#xff0c;txt和md是纯文本文件。 小结 IO流体系 FileOutputStream public class Demo1 {public static void main(String[] args)…

【学习笔记】 使用AD24完成相同电路的自动布线布局(相同模块布局布线ROOM布线快速克隆)

【学习笔记】 使用AD24完成相同电路的自动布线布局 一、适用基本条件二、基于ROOM的自动布局/布线的方法三、可能出现的报错四、ROOM自动布局的一些优点和缺点 当面对多个相同电路模块时&#xff0c;使用 ROOM 可以一次性对一个模块进行精心布局&#xff0c;然后将该布局快速复…

2024 研究生数学建模竞赛(C题)建模秘籍|数据驱动下磁性元件的磁芯损耗建模|文章代码思路大全

铛铛&#xff01;小秘籍来咯&#xff01; 小秘籍团队独辟蹊径&#xff0c;运用数据拟合&#xff0c;方差分析&#xff08;ANOVA&#xff09;&#xff0c;特征提取&#xff0c;多目标优化等强大工具&#xff0c;构建了这一题的详细解答哦&#xff01; 为大家量身打造创新解决方案…

vs2022快捷键异常不起作用解决办法

安装了新版本的vs2022&#xff0c;安装成功后&#xff0c;发现快捷键发生异常&#xff0c;之前常用的快捷键要么发生改变&#xff0c;要么无法使用&#xff0c;比如原来注释代码的快捷键是ctrlec&#xff0c;最新安装版本变成了ctrlkc&#xff0c;以前编译代码的快捷键是F6或者…

go webapi上传文件 部属到linux

go厉害的地方&#xff0c;linux服务器上无需安装任务依赖就可以运行&#xff0c;大赞&#xff01; 一、编译 #在Goland中cmd中执行 go env -w GOARCHamd64 go env -w GOOSlinux go build main.go # 切换回来 否则无法运行 go env -w GOOSwindows go run main.go 拷贝到linux服…

ubuntu如何进行自动mount硬盘(简易法)

1. 找到你ubuntu的disk工具 2. 选中你要mount的盘 3. 点击那个设置按钮 4. 选择edit mount options 5. disable user session defaults 6, 填写Mount Point就可以了&#xff0c; 最后输入一次密码&#xff0c;重启设备就搞定了

DOG:知识图谱大模型问答的迭代交互式推理,克服长路径和假阳性关系挑战

DOG&#xff1a;知识图谱大模型问答的迭代交互式推理&#xff0c;克服长路径和假阳性关系挑战 秒懂大纲提出背景解法拆解全流程优化和医学关系 创意 秒懂大纲 ├── DoG框架【主题】 │ ├── 背景【研究背景】 │ │ ├── LLMs的局限性【问题描述】 │ │ │ …

pgvector docker版安装;稀疏向量使用;psycopg2 python连接使用

参看: https://cloud.tencent.com/developer/article/2359831 https://hub.docker.com/r/pgvector/pgvector/tags https://github.com/pgvector/pgvector 一、安装 拉取0.7版本 docker pull pgvector/pgvector:0.7.4-pg16运行: docker run --name pgvector -v $(pwd)/dat…

OpenLayers 开源的Web GIS引擎 - 地图初始化

在线引用&#xff1a; 地址&#xff1a;OpenLayers - Get the Code 离线引用&#xff1a; 下载地址&#xff1a;Releases openlayers/openlayers GitHub v10.0.0版本 地图初始化代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><…

Spring Boot 入门:解锁 Spring 全家桶

前言 Spring 全家桶是现代 Java 开发者不可或缺的工具集&#xff0c;它提供了从轻量级的框架到微服务架构的完整支持。本文将带你快速了解 Spring 框架、核心概念如 IoC&#xff08;控制反转&#xff09;和 AOP&#xff08;面向切面编程&#xff09;&#xff0c;并深入介绍 Sp…

Java项目实战II基于Java+Spring Boot+MySQL的网上租贸系统设计与实现(开发文档+源码+数据库)

目录 一、前言 二、技术介绍 三、系统实现 四、论文参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 "随着…

hpux B.11.31 安装 JDK(详细步骤、多图预警)

目录 零、测试环境 一、获取 JDK 安装包 二、安装 JDK 1、操作指南 2、安装流程 &#xff08;1&#xff09;选中 Java JDK &#xff08;2&#xff09;&#xff08;可选&#xff09;选择安装目录 &#xff08;3&#xff09;点击安装 &#xff08;4&#xff09;&#xf…

CefSharp_Vue交互(Element UI)_WinFormWeb应用(4)--- 最小化最大化关闭窗体交互(含示例代码)

一、效果预览 实现功能,通过vue页面模仿窗体的三个功能按钮实现最小化最大化关闭功能 1.1 预览 1.2 代码 页面代码