展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > Python Asyncio库中常用的同步原语函数有哪些?

Python Asyncio库中常用的同步原语函数有哪些?

前记Asyncio的同步原语可以简化我们编写资源竞争的代码和规避资源竞争导致的Bug的出现。但是由于协程的特性,在大部分业务代码中并不需要去考虑资源竞争的出现,导致Asyncio同步原语被使用的频率比较低,但是如果想基于Asyncio编写框架则需要学习同步原语的使用。0.基础同步原语都是适用于某些条件下对某个资源的争夺,在代码中大部分的资源都是属于一个代码块,而Python对于代码块的管理的最佳实践是使用with语法,with语法实际上是调用了一个类中的__enter__和__exit__方法,比如下面的

本文目录

    前记

    Asyncio的同步原语可以简化我们编写资源竞争的代码和规避资源竞争导致的Bug的出现。 但是由于协程的特性,在大部分业务代码中并不需要去考虑资源竞争的出现,导致Asyncio同步原语被使用的频率比较低,但是如果想基于Asyncio编写框架则需要学习同步原语的使用。

    0.基础

    同步原语都是适用于某些条件下对某个资源的争夺,在代码中大部分的资源都是属于一个代码块,而Python对于代码块的管理的最佳实践是使用with语法,with语法实际上是调用了一个类中的__enter__和__exit__方法,比如下面的代码:

    class Demo(object):
        def __enter__(self):
            return 
        def __exit__(self, exc_type, exc_val, exc_tb):
            return 
    with Demo():
        pass

    代码中的Demo类实现了__enter__和__exit__方法后,就可以被with语法调用,其中__enter__方法是进入代码块执行的逻辑,__enxi__方法是用于退出代码块(包括异常退出)的逻辑。这两个方法符合同步原语中对资源的争夺和释放,但是__enter__和__exit__两个方法都是不支持await调用的,为了解决这个问题,Python引入了async with语法。

    async with语法和with语法类似 ,我们只要编写一个拥有__aenter__和__aexit__方法的类,那么这个类就支持asyncio with语法了,如下:

    import asyncio
    class Demo(object):
        async def __aenter__(self):
            return
        async def __aexit__(self, exc_type, exc_val, exc_tb):
            return
    async def main():
        async with Demo():
            pass
    asyncio.run(main())

    其中,类中的__aenter__方法是进入代码块时执行的方法,__aexit__是退出代码块时执行的方法。

    有了async with语法的加持,asyncio的同步原语使用起来会比较方便,所以asyncio中对资源争夺的同步原语都会继承于_ContextManagerMixin类:

    class _ContextManagerMixin:
        async def __aenter__(self):
            await self.acquire()
            # We have no use for the "as ..."  clause in the with
            # statement for locks.
            return None
        async def __aexit__(self, exc_type, exc, tb):
            self.release()

    并实现了acquire和release方法,供__aenter__和__aexit__方法调用,同时我们在使用同步原语的时候尽量用到async with语法防止忘记释放资源的占用。

    1.Lock

    由于协程的特性,在编写协程代码时基本上可以不考虑到锁的情况,但在一些情况下我们还是需要用到锁,并通过锁来维护并发时的数据安全性,如下例子:

    import asyncio
    share_data = {}
    async def sub(i):
        # 赋上相同的key和value
        share_data[i] = i
        await asyncio.sleep(0)
        print(i, share_data[i] == i)
    async def sub_add(i):
        # 赋上的value值是原来的+1
        share_data[i] = i + 1
        await asyncio.sleep(0)
        print(i, share_data[i] == i + 1)
    async def main():
        # 创建并发任务
        task_list = []
        for i in range(10):
            task_list.append(sub(i))
            task_list.append(sub_add(i))
        # 并发执行
        await asyncio.gather(*task_list)
    if __name__ == "__main__":
        asyncio.run(main())

    在这个例子中程序会并发的执行sub和sub_add函数,他们是由不同的asyncio.Task驱动的,这意味着会出现这样一个场景。 当负责执行sub(1)函数的asyncio.Task在执行完share_data[i]=i后就执行await asyncio.sleep(0)从而主动让出控制权并交还给事件循环,等待事件循环的下一次调度。 不过事件循环不会空下来,而是马上安排下一个asyncio.Task执行,此时会先执行到sub_add(1)函数的share_data[i] = i + 1,并同样的在执行到await asyncio.sleep(0)的时候把控制权交会给事件循环。 这时候控制权会由事件循环转移给原先执行sub(1)函数的asyncio.Task,获取到控制权l后sub(1)函数的逻辑会继续走,但由于share_data[i]的数据已经被share_data[i] = i + 1修改了,导致最后执行print时,share_data[i]的数据已经变为脏数据,而不是原本想要的数据了。

    为了解决这个问题,我们可以使用asyncio.Lock来解决资源的冲突,如下:

    import asyncio
    share_data = {}
    # 存放对应资源的锁
    lock_dict = {}
    async def sub(i):
        async with lock_dict[i]:  # <-- 通过async with语句来控制锁的粒度
            share_data[i] = i
            await asyncio.sleep(0)
            print(i, share_data[i] == i)
    async def sub_add(i):
        async with lock_dict[i]:
            share_data[i] = i + 1
            await asyncio.sleep(0)
            print(i, share_data[i] == i + 1)
    async def main():
        task_list = []
        for i in range(10):
            lock_dict[i] = asyncio.Lock()
            task_list.append(sub(i))
            task_list.append(sub_add(i))
        await asyncio.gather(*task_list)
    if __name__ == "__main__":
        asyncio.run(main())

    从例子可以看到asyncio.Lock的使用方法跟多线程的Lock差不多,通过async with语法来获取和释放锁,它的原理也很简单,主要做了如下几件事:

    • 1.确保某一协程获取锁后的执行期间,别的协程在获取锁时需要一直等待,直到执行完成并释放锁。

    • 2.当有协程持有锁的时候,其他协程必须等待,直到持有锁的协程释放了锁。

    • 2.确保所有协程能够按照获取的顺序获取到锁。

    这意味着需要有一个数据结构来维护当前持有锁的协程的和下一个获取锁协程的关系,同时也需要一个队列来维护多个获取锁的协程的唤醒顺序。

    asyncio.Lock跟其它asyncio功能的用法一样,使用asyncio.Future来同步协程之间锁的状态,使用deque维护协程间的唤醒顺序,源码如下:

    class Lockl(_ContextManagerMixin, mixins._LoopBoundMixin):
        def __init__(self):
            self._waiters = None
            self._locked = False
        def locked(self):
            return self._locked
        async def acquire(self):
            if (not self._locked and (self._waiters is None or all(w.cancelled() for w in self._waiters))):
                # 目前没有其他协程持有锁,当前协程可以运行
                self._locked = True
                return True
            if self._waiters is None:
                self._waiters = collections.deque()
            # 创建属于自己的容器,并推送到`_waiters`这个双端队列中
            fut = self._get_loop().create_future()
            self._waiters.append(fut)
            try:
                try:
                    await fut
                finally:
                    # 如果执行完毕,需要把自己移除,防止被`wake_up_first`调用
                    self._waiters.remove(fut)
            except exceptions.CancelledError:
                # 如果是等待的过程中被取消了,需要唤醒下一个调用`acquire`
                if not self._locked:
                    self._wake_up_first()
                raise
            # 持有锁
            self._locked = True
            return True
        def release(self):
            if self._locked:
                # 释放锁
                self._locked = False
                self._wake_up_first()
            else:
                raise RuntimeError('Lock is not acquired.')
        def _wake_up_first(self):
            if not self._waiters:
                return
            # 获取还处于锁状态协程对应的容器
            try:
                # 获取下一个等待获取锁的waiter
                fut = next(iter(self._waiters))
            except StopIteration:
                return
            # 设置容器为True,这样对应协程就可以继续运行了。
            if not fut.done():
                fut.set_result(True)

    通过源码可以知道,锁主要提供了获取和释放的功能,对于获取锁需要区分两种情况:

    • 1:当有协程想要获取锁时会先判断锁是否被持有,如果当前锁没有被持有就直接返回,使协程能够正常运行。

    • 2:如果协程获取锁时,锁发现自己已经被其他协程持有则创建一个属于当前协程的asyncio.Future,用来同步状态,并添加到deque中。

    而对于释放锁就比较简单,只要获取deque中的第一个asyncio.Future,并通过fut.set_result(True)进行标记,使asyncio.Future从peding状态变为done状态,这样一来,持有该asyncio.Future的协程就能继续运行,从而持有锁。

    不过需要注意源码中acquire方法中对CancelledError异常进行捕获,再唤醒下一个锁,这是为了解决acquire方法执行异常导致锁一直被卡住的场景,通常情况下这能解决大部分的问题,但是如果遇到错误的封装时,我们需要亲自处理异常,并执行锁的唤醒。比如在通过继承asyncio.Lock编写一个超时锁时,最简单的实现代码如下:

    import asyncio
    class TimeoutLock(asyncio.Lock):
        def __init__(self, timeout, *, loop=None):
            self.timeout = timeout
            super().__init__(loop=loop)
        async def acquire(self) -> bool:
            return await asyncio.wait_for(super().acquire(), self.timeout)

    这份代码非常简单,他只需要在__init__方法传入timeout参数,并在acuiqre方法中通过wait_for来实现锁超时即可,现在假设wait_for方法是一个无法传递协程cancel的方法,且编写的acquire没有进行捕获异常再释放锁的操作,当异常发生的时候会导致锁一直被卡住。 为了解决这个问题,只需要对TimeoutLock的acquire方法添加异常捕获,并在捕获到异常时释放锁即可,代码如下:

    class TimeoutLock(asyncio.Lock):
        def __init__(self, timeout, *, loop=None):
            self.timeout = timeout
            super().__init__(loop=loop)
        async def acquire(self) -> bool:
            try:
                return await asyncio.wait_for(super().acquire(), self.timeout)
            except Exception:
                self._wake_up_first()
                raise

    2.Event

    asyncio.Event也是一个简单的同步原语,但它跟asyncio.Lock不一样,asyncio.Lock是确保每个资源只能被一个协程操作,而asyncio.Event是确保某个资源何时可以被协程操作,可以认为asyncio.Lock锁的是资源,asyncio.Event锁的是协程,所以asyncio.Event并不需要acquire来锁资源,release释放资源,所以也用不到async with语法。

    asyncio.Event的简单使用示例如下:

    import asyncio
    async def sub(event: asyncio.Event) -> None:
        await event.wait()
        print("I'm Done")
    async def main() -> None:
        event = asyncio.Event()
        for _ in range(10):
            asyncio.create_task(sub(event))
        await asyncio.sleep(1)
        event.set()
    asyncio.run(main())

    在这个例子中会先创建10个asyncio.Task来执行sub函数,但是所有sub函数都会在event.wait处等待,直到main函数中调用event.set后,所有的sub函数的event.wait会放行,使sub函数能继续执行。

    可以看到asyncio.Event功能比较简单,它的源码实现也很简单,源码如下:

    class Event(mixins._LoopBoundMixin):
        def __init__(self):
            self._waiters = collections.deque()
            self._value = False
        def is_set(self):
            return self._value
        def set(self):
            if not self._value:
                # 确保每次只能set一次
                self._value = True
                # 设置每个协程存放的容器为True,这样对应的协程就可以运行了
                for fut in self._waiters:
                    if not fut.done():
                        fut.set_result(True)
        def clear(self):
            # 清理上一次的set
            self._value = False
        async def wait(self):
            if self._value:
                # 如果设置了,就不需要等待了
                return True
            # 否则需要创建一个容器,并需要等待容器完成
            fut = self._get_loop().create_future()
            self._waiters.append(fut)
            try:
                await fut
                return True
            finally:
                self._waiters.remove(fut)

    通过源码可以看到wait方法主要是创建了一个asyncio.Future,并把它加入到deque队列后就一直等待着,而set方法被调用时会遍历整个deque队列,并把处于peding状态的asyncio.Future设置为done,这时其他在调用event.wait方法的协程就会得到放行。

    通过源码也可以看出,asyncio.Event并没有继承于_ContextManagerMixin,这是因为它锁的是协程,而不是资源。

    asyncio.Event的使用频率比asyncio.Lock多许多,不过通常都会让asyncio.Event和其他数据结构进行封装再使用,比如实现一个服务器的优雅关闭功能,这个功能会确保服务器在等待n秒后或者所有连接都关闭后才关闭服务器,这个功能就可以使用set与asyncio.Event结合,如下:

    import asyncio
    class SetEvent(asyncio.Event):
        def __init__(self, *, loop=None):
            self._set = set()
            super().__init__(loop=loop)
        def add(self, value):
            self._set.add(value)
            self.clear()
        def remove(self, value):
            self._set.remove(value)
            if not self._set:
                self.set()

    这个SetEvent结合了set和SetEvent的功能,当set有数据的时候,会通过clear方法使SetEvent变为等待状态,而set没数据的时候,会通过set方法使SetEvent变为无需等待的状态,所有调用wait的协程都可以放行,通过这种结合,SetEvent拥有了等待资源为空的功能。 接下来就可以用于服务器的优雅退出功能:

    async def mock_conn_io() -> None:
        await asyncio.sleep(1)
    def conn_handle(set_event: SetEvent):
        task: asyncio.Task = asyncio.create_task(mock_conn_io())
        set_event.add(task)
        task.add_done_callback(lambda t: set_event.remove(t))
    async def main():
        set_event: SetEvent = SetEvent()
        for _ in range(10):
            conn_handle(set_event)
    	# 假设这里收到了退出信号
        await asyncio.wait(set_event.wait(), timeout=9)
    asyncio.run(main())

    在这个演示功能中,mock_conn_io用于模拟服务器的连接正在处理中,而conn_handle用于创建服务器连接,main则是先创建10个连接,并模拟在收到退出信号后等待资源为空或者超时才退出服务。

    这只是简单的演示,实际上的优雅关闭功能要考虑的东西不仅仅是这些。

    4.Condition

    condition只做简单介绍

    asyncio.Condition是同步原语中使用最少的一种,因为他使用情况很奇怪,而且大部分场景可以被其他写法代替,比如下面这个例子:

    import asyncio
    async def task(condition, work_list):
        await asyncio.sleep(1)
        work_list.append(33)
        print('Task sending notification...')
        async with condition:
            condition.notify()
    async def main():
        condition = asyncio.Condition()
        work_list = list()
        print('Main waiting for data...')
        async with condition:
            _ = asyncio.create_task(task(condition, work_list))
            await condition.wait()
        print(f'Got data: {work_list}')
    asyncio.run(main())
    # >>> Main waiting for data...
    # >>> Task sending notification...
    # >>> Got data: [33]

    在这个例子中可以看到,notify和wait方法只能在async with condition中可以使用,如果没有在async with condition中使用则会报错,同时这个示例代码有点复杂,没办法一看就知道执行逻辑是什么,其实这个逻辑可以转变成一个更简单的写法:

    import asyncio
    async def task(work_list):
        await asyncio.sleep(1)
        work_list.append(33)
        print('Task sending notification...')
        return
    async def main():
        work_list = list()
        print('Main waiting for data...')
        _task = asyncio.create_task(task(work_list))
        await _task
        print(f'Got data: {work_list}')
    asyncio.run(main())
    # >>> Main waiting for data...
    # >>> Task sending notification...
    # >>> Got data: [33]

    通过这个代码可以看到这个写法更简单一点,而且更有逻辑性,而condition的写法却更有点Go协程写法/或者回调函数写法的感觉。 所以建议在认为自己的代码可能会用到asyncio.Conditon时需要先考虑到是否需要asyncio.Codition?是否有别的方案代替,如果没有才考虑去使用asyncio.Conditonk。

    5.Semaphore

    asyncio.Semaphore--信号量是同步原语中被使用最频繁的,大多数都是用在限流场景中,比如用在爬虫中和客户端网关中限制请求频率。

    asyncio.Semaphore可以认为是一个延缓触发的asyncio.Lock,asyncio.Semaphore内部会维护一个计数器,无论何时进行获取或释放,它都会递增或者递减(但不会超过边界值),当计数器归零时,就会进入到锁的逻辑,但是这个锁逻辑会在计数器大于0的时候释放j,它的用法如下:`

    import asyncio
    async def main():
        semaphore = asyncio.Semaphore(10):
        async with semaphore:
            pass
    asyncio.run(main())

    示例中代码通过async with来指明一个代码块(代码用pass代替),这个代码块是被asyncio.Semaphore管理的,每次协程在进入代码块时,asyncio.Semaphore的内部计数器就会递减一,而离开代码块则asyncio.Semaphore的内部计数器会递增一。

    当有一个协程进入代码块时asyncio.Semaphore发现计数器已经为0了,则会使当前协程进入等待状态,直到某个协程离开这个代码块时,计数器会递增一,并唤醒等待的协程,使其能够进入代码块中继续执行。

    asyncio.Semaphore的源码如下,需要注意的是由于asyncio.Semaphore是一个延缓的asyncio.Lock,所以当调用一次release后可能会导致被唤醒的协程和刚进入代码块的协程起冲突,所以在acquire方法中要通过一个while循环来解决这个问题:`

    class Semaphore(_ContextManagerMixin, mixins._LoopBoundMixin):
        def __init__(self, value=1):
            if value < 0:
                raise ValueError("Semaphore initial value must be >= 0")
            self._value = value
            self._waiters = collections.deque()
            self._wakeup_scheduled = False
        def _wake_up_next(self):
            while self._waiters:
                # 按照放置顺序依次弹出容器 
                waiter = self._waiters.popleft()
                if not waiter.done():
                    # 设置容器状态,使对应的协程可以继续执行
                    waiter.set_result(None)
                    # 设置标记 
                    self._wakeup_scheduled = True
                    return
        def locked(self):
            return self._value == 0
        async def acquire(self):
            # 如果`self._wakeup_scheduled`为True或者value小于0
            while self._wakeup_scheduled or self._value <= 0:
                # 创建容器并等待执行完成
                fut = self._get_loop().create_future()
                self._waiters.append(fut)
                try:
                    await fut
                    self._wakeup_scheduled = False
                except exceptions.CancelledError:
                    # 如果被取消了,也要唤醒下一个协程
                    self._wake_up_next()
                    raise
            self._value -= 1
            return True
        def release(self):
            # 释放资源占用,唤醒下一个协程。
            self._value += 1
            self._wake_up_next()

    针对asyncio.Semaphore进行修改可以实现很多功能,比如基于信号量可以实现一个简单的协程池,这个协程池可以限制创建协程的量,当协程池满的时候就无法继续创建协程,只有协程中的协程执行完毕后才能继续创建(当然无法控制在协程中创建新的协程),代码如下:

    import asyncio
    import time
    from typing import Coroutine
    class Pool(object):
        def __init__(self, max_concurrency: int):
            self._semaphore: asyncio.Semaphore = asyncio.Semaphore(max_concurrency)
        async def create_task(self, coro: Coroutine) -> asyncio.Task:
            await  self._semaphore.acquire()
            task: asyncio.Task = asyncio.create_task(coro)
            task.add_done_callback(lambda t: self._semaphore.release())
            return task
    async def demo(cnt: int) -> None:
        print(f"{int(time.time())} create {cnt} task...")
        await  asyncio.sleep(cnt)
    async def main() -> None:
        pool: Pool = Pool(3)
        for i in range(10):
            await pool.create_task(demo(i))
    asyncio.run(main())
    # >>> 1677517996 create 0 task...
    # >>> 1677517996 create 1 task...
    # >>> 1677517996 create 2 task...
    # >>> 1677517996 create 3 task...
    # >>> 1677517997 create 4 task...
    # >>> 1677517998 create 5 task...
    # >>> 1677517999 create 6 task...
    # >>> 1677518001 create 7 task...
    # >>> 1677518003 create 8 task...
    # >>> 1677518005 create 9 task...
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Python
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirServer Windows版
    AirServer Windows版

    AirServer Windows版可把电脑变成AirPlay、Google Cast和Miracast无线投屏接收端,适合会议演示、课堂教学及家庭大屏分享。发送设备通常无需另装客户端,并可同时接收和智能排列多个镜像会话。