返回顶部
首页 > 资讯 > 后端开发 > Python >Python Asyncio库之同步原语常用函数有哪些
  • 727
分享到

Python Asyncio库之同步原语常用函数有哪些

2023-07-05 07:07:01 727人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

这篇文章主要讲解了“python Asyncio库之同步原语常用函数有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python Asyncio库之同步原语常用函数有

这篇文章主要讲解了“python Asyncio库之同步原语常用函数有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python Asyncio库之同步原语常用函数有哪些”吧!

前记

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 asyncioclass Demo(object):    async def __aenter__(self):        return    async def __aexit__(self, exc_type, exc_val, exc_tb):        returnasync def main():    async with Demo():        passasyncio.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()

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

1.Lock

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

import asynciOShare_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())

在这个例子中程序会并发的执行subsub_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 asyncioshare_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语法来获取和释放锁,它的原理也很简单,主要做了如下几件事:

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

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

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

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

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)

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

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

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

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

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

import asyncioclass 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没有进行捕获异常再释放锁的操作,当异常发生的时候会导致锁一直被卡住。 为了解决这个问题,只需要对TimeoutLockacquire方法添加异常捕获,并在捕获到异常时释放锁即可,代码如下:

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 asyncioasync 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秒后或者所有连接都关闭后才关闭服务器,这个功能就可以使用setasyncio.Event结合,如下:

import asyncioclass 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结合了setSetEvent的功能,当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 asyncioasync 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())# &gt;&gt;&gt; Main waiting for data...# &gt;&gt;&gt; Task sending notification...# &gt;&gt;&gt; Got data: [33]

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

import asyncioasync def task(work_list):    await asyncio.sleep(1)    work_list.append(33)    print('Task sending notification...')    returnasync 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())# &gt;&gt;&gt; Main waiting for data...# &gt;&gt;&gt; Task sending notification...# &gt;&gt;&gt; Got data: [33]

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

5.Semaphore

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

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

import asyncioasync def main():    semaphore = asyncio.Semaphore(10):    async with semaphore:        passasyncio.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 asyncioimport timefrom typing import Coroutineclass 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 taskasync 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...

感谢各位的阅读,以上就是“Python Asyncio库之同步原语常用函数有哪些”的内容了,经过本文的学习后,相信大家对Python Asyncio库之同步原语常用函数有哪些这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: Python Asyncio库之同步原语常用函数有哪些

本文链接: https://lsjlt.com/news/350429.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Python Asyncio库之同步原语常用函数有哪些
    这篇文章主要讲解了“Python Asyncio库之同步原语常用函数有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python Asyncio库之同步原语常用函数有...
    99+
    2023-07-05
  • Python Asyncio 库之同步原语常用函数详解
    目录前记0.基础1.Lock2.Event4.Condition5.Semaphore前记 Asyncio的同步原语可以简化我们编写资源竞争的代码和规避资源竞争导致的Bug的出现。...
    99+
    2023-03-01
    Python Asyncio 库同步原语 Python Asyncio 函数
  • Python Asyncio库之asyncio.task常用函数有哪些
    0.基础在《Python Asyncio调度原理》中介绍了Asyncio的两种调度基本单位,Handler和TimeHandler,他们只能被loop.call_xx函数调用,开发者从表面上不知道他们的存在,他们和loop.call_xx属...
    99+
    2023-05-14
    Python asyncio
  • Python Asyncio库之asyncio.task常用函数详解
    目录前记0.基础1.休眠--asyncio.sleep2.屏蔽取消--asyncio.shield3.超时--asyncio.wait_for4.简单的等待--wait5.迭代可等待...
    99+
    2023-03-01
    Python Asyncio asyncio.task Python Asyncio Python asyncio.task
  • Python之random库的常用函数有哪些
    目录前言一 random库介绍二 基本随机函数三 扩展随机函数1. randint()2. uniform()3. randrange()4. choice()5. shuffle(...
    99+
    2024-04-02
  • Python中random库有哪些常用函数
    这篇文章主要为大家展示了“Python中random库有哪些常用函数”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Python中random库有哪些常用函数”这篇文章吧。一 random库介绍在...
    99+
    2023-06-29
  • urllib库常用函数有哪些
    这篇文章主要介绍了urllib库常用函数有哪些的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇urllib库常用函数有哪些文章都会有所收获,下面我们一起来看看吧。一、什么是 urllib 库?  &nb...
    99+
    2023-06-27
  • pandas库有哪些常用函数
    pandas库常用函数有:1、read_csv()和read_excel()函数;2、head()和tail()函数;3、info()函数;4、describe()函数等。详细介绍:1、read_csv()和read_excel()函数,这...
    99+
    2023-11-22
    Pandas 常用函数
  • mysql数据库同步报错的原因有哪些
    数据库同步报错可能有多种原因,以下是一些可能的原因: 网络连接问题:数据库同步过程中出现网络连接问题会导致同步失败。 权限问题:同...
    99+
    2024-03-06
    mysql
  • Python之shutil模块常用的函数有哪些
    这篇文章主要讲解了“Python之shutil模块常用的函数有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python之shutil模块常用的函数有哪些”吧!shutil 是 Pyth...
    99+
    2023-06-16
  • Python最常用的函数、基础语句有哪些?
    一、内置函数内置函数是python自带的函数方法,拿来就可以用,比方说zip、filter、isinstance等。下面是Python官档给出的内置函数列表,相当的齐全。下面几个是常见的内置函数:1、​​​enumerate​​​(iter...
    99+
    2023-05-14
    Python 编程语言
  • 聊聊 Python 最常用的语句、函数有哪些?
    一、内置函数内置函数是python自带的函数方法,拿来就可以用,比方说zip、filter、isinstance等下面是Python官档给出的内置函数列表,相当的齐全下面几个是常见的内置函数:1、enumerate(iterable,sta...
    99+
    2023-05-14
    Python 函数 模块
  • python常用函数模块有哪些
    python中常用的函数模块有以下几种Urllib3Urllib3是一个Python的HTTP客户端,具有线程安全、连接池、客户端 SSL/TLS 验证等功能。SixSix是一个是Python2和Python3的兼容性库,旨在支持可同时运行...
    99+
    2024-04-02
  • python中常用的函数有哪些
    python中常用的函数有以下几种print()函数:打印字符串。raw_input()函数:从用户键盘捕获字符。len()函数:计算字符长度。format函数:格式化输出。type()函数:查询对象的类型。int()函数、float()函...
    99+
    2024-04-02
  • Python中有哪些常用的函数
    这篇文章主要讲解了“Python中有哪些常用的函数”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python中有哪些常用的函数”吧!shutil 是 Python 中的高级文件操作模块,与o...
    99+
    2023-07-05
  • 数据库常用sql语句有哪些
    常用的数据库SQL语句包括:1. SELECT:从数据库中查询数据2. INSERT:向数据库中插入新的数据3. UPDATE:更新...
    99+
    2023-09-05
    SQL 数据库
  • Python有哪些最常用的函数和基础语句
    这篇文章主要介绍了Python有哪些最常用的函数和基础语句的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Python有哪些最常用的函数和基础语句文章都会有所收获,下面我们一起来看看吧。内置函数内置函数是pyth...
    99+
    2023-07-06
  • 不同语言中,PHP函数的独特之处有哪些?
    php 函数的独特之处在于其动态类型化、可接收代码块作为参数、可定义可变数量的参数。实战案例包括:以匿名函数传递数字数组来计算总和;使用可变数量的参数传递数组来打印其内容。 PHP 函...
    99+
    2024-04-19
    函数 php
  • Go语言中常用的函数有哪些?
    Go语言中常用的函数有哪些?————探究Go语言中常用的函数及其用法 作为一门流行的静态类型编程语言,Go语言广泛应用于各种领域,如服务器端开发、网络编程、云计算等。在Go语言中,函数...
    99+
    2024-04-02
  • 常用的Python内置函数有哪些
    这篇文章主要为大家展示了“常用的Python内置函数有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“常用的Python内置函数有哪些”这篇文章吧。内置函数简介Python 解释器自带的函数叫...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作