程序代码篇—python回调函数&异步编程


文章目录

  • 前言
  • 第一部分:Python的回调函数
  • 1.基本概念
  • 2.如何实现
  • 定义回调函数:
  • 定义主函数:
  • 例子
  • 3.回调函数的应用场景
  • 事件处理
  • 异步编程
  • 库和框架
  • 注意事项
  • 调用时机
  • 错误处理
  • 闭包
  • 第二部分:async和await关键字
  • 1.异步编程的概念
  • 2.async
  • 定义
  • 用法
  • 特性
  • 3.await
  • 定义
  • 用法
  • 特性
  • 4.异步编程的例子
  • 5.注意事项
  • 总结

  • 前言

    以上就是今天要讲的内容,本文简单介绍了Python中的回调函数以及异步编程。


    第一部分:Python的回调函数

    在Python中,回调函数是一种编程范式,它允许我们将一个函数作为参数传递给另一个函数。这个作为参数传递的函数(即回调函数)可以在另一个函数执行到某个点时被调用。回调函数在事件驱动编程、异步编程和某些库和框架中非常常见。

    以下是关于回调函数的详细解释:

    1.基本概念

    定义:回调函数是一个你定义的函数,但不是由你来调用。你将这个函数作为参数传递给另一个函数,这个另一个函数在适当的时候会调用你的函数。
    目的:回调函数允许代码的模块化和解耦,使得我们可以编写更灵活和可重用的代码。

    2.如何实现

    定义回调函数:

    这只是一个普通的函数,可以接受任意数量的参数。

    def my_callback_function(param):
        print(f"Callback function called with {param}")
    

    定义主函数:

    主函数接受一个函数作为参数,这个参数就是回调函数。

    def main_function(callback):
        # 做一些操作
        # ...
        # 调用回调函数
        callback("some data")
    

    调用主函数,传递回调:
    当调用main_function时,我们将my_callback_function作为参数传递。

    main_function(my_callback_function)
    

    例子

    下面是一个完整的例子,演示了如何使用回调函数:

    def print_hello(name):
        print(f"Hello, {name}")
    
    def greeter(callback, name):
        callback(name)
    

    使用print_hello作为回调函数

    greeter(print_hello, "Alice")
    

    运行这段代码,输出将是:

    Hello, Alice
    

    3.回调函数的应用场景

    事件处理

    事件处理:在**图形用户界面(GUI)**编程中,当用户执行某些操作(如点击按钮)时,可以注册一个回调函数来响应事件。

    异步编程

    异步编程:在执行异步操作(如网络请求、文件I/O)时,可以提供一个回调函数,以便在操作完成时执行。

    库和框架

    库和框架:许多库和框架允许你传入回调函数来自定义其行为,例如排序函数、过滤函数等。

    注意事项

    调用时机

    调用时机:回调函数可能在任何时候被调用,这取决于主函数的实现。

    错误处理

    错误处理:回调函数中的错误可能会影响主函数的执行,因此需要妥善处理。

    闭包

    闭包:如果回调函数在定义它的作用域之外被调用,它可能形成一个闭包,能够访问定义时的作用域中的变量。
    通过使用回调函数,Python程序员可以编写更加灵活和可扩展的代码。不过,也需要注意回调地狱(callback hell)的问题,即当回调函数嵌套太多层时,代码会变得难以理解和维护。为了解决这个问题,可以使用异步编程的async和await关键字,或者使用Promise等模式

    第二部分:async和await关键字

    1.异步编程的概念

    异步编程是一种编程范式,允许程序在等待某些操作(如I/O操作、网络请求等)完成时继续执行其他任务。这与传统的同步编程相反,在同步编程中,程序在等待一个操作完成时会阻塞,直到该操作完成。

    2.async

    定义

    定义:async是一个用于定义异步函数的关键字。异步函数与普通函数不同,它们在执行时可以暂停并在适当的时候恢复执行

    用法

    用法:将async关键字放在函数定义的前面,如下所示:

    async def my_async_function():
    

    特性

    特性:异步函数在调用时不会立即执行,而是返回一个协程对象(coroutine object)。协程对象需要通过事件循环(event loop)来调度执行

    3.await

    定义

    定义:await关键字用于等待一个协程完成。它只能在异步函数内部使用

    用法

    用法:在异步函数内部,使用await关键字调用另一个异步函数

    async def another_async_function():
    
    await some_async_operation()
    

    特性

    特性:当await被调用时,它会暂停当前协程的执行,直到被等待的协程完成。在此期间,事件循环可以运行其他协程

    4.异步编程的例子

    以下是一个使用async和await的简单例子:

    import asyncio
    
    async def say_after(delay, what):
        await asyncio.sleep(delay)
        print(what)
    
    async def main():
        print(f"started at {time.strftime('%X')}")
    
        await say_after(1, 'hello')
        await say_after(2, 'world')
    
        print(f"finished at {time.strftime('%X')}")
    
    asyncio.run(main())
    

    在这个例子中:

    1. say_after是一个异步函数,它等待指定的延迟时间后打印一条消息
    2. main也是一个异步函数,它调用say_after两次,每次等待不同的时间。
    3. asyncio.run(main())是启动事件循环并运行main协程的方法
    4. 顺序执行但非阻塞:虽然say_after函数是顺序调用的,但它们是异步执行的。这意味着在等待say_after(1, ‘hello’)完成时,程序不会阻塞,而是可以继续执行其他操作(如果有)。在这个例子中,由于没有其他操作,所以实际上它是顺序执行的。
    5. 并发潜力:如果有其他异步任务需要执行,它们可以在等待say_after函数完成时并发执行。例如,如果有另一个异步函数do_something_else,你可以在await say_after(1, ‘hello’)之后立即调用它,而不需要等待’hello’打印完成。
    6. 资源效率:异步编程允许单线程程序在等待I/O操作(如asyncio.sleep模拟的)完成时执行其他任务。这比使用多线程来处理并发I/O操作要高效得多,因为多线程会增加上下文切换的开销。
    import asyncio
    import time
    
    async def say_after(delay, what):
        await asyncio.sleep(delay)
        print(what)
    
    async def main():
        print(f"started at {time.strftime('%X')}")
    
        # 创建两个协程
        task1 = asyncio.create_task(say_after(1, 'hello'))
        task2 = asyncio.create_task(say_after(2, 'world'))
    
        # 不等待每个协程单独完成,而是并发地运行它们
        # 这里的await不会阻塞其他协程的执行
        await task1
        await task2
    
        print(f"finished at {time.strftime('%X')}")
    
    asyncio.run(main())
    

    在这个修改后的版本中,我们使用了asyncio.create_task()来创建两个任务,这两个任务会并发执行。这里的关键是,await关键字现在用于等待两个任务的同时完成,而不是分别等待每个say_after函数。由于这两个任务是并发执行的,所以整体程序的执行时间将接近于最长的单个任务执行时间(在这个例子中是2秒),而不是各个任务执行时间的总和(原来的3秒)。

    5.注意事项

    1. 只能在异步函数中使用await:await关键字只能在async def定义的异步函数中使用
    2. 事件循环:异步函数需要事件循环来运行。asyncio.run()是一个便捷的方法来运行最高层级的异步函数。
    3. 并发与并行:asyncio提供的是并发而不是并行。虽然多个协程可以并发执行,但它们实际上是在单个线程中通过事件循环进行调度。
    4. 性能考虑:异步编程可以提高I/O密集型应用程序的性能,但对于CPU密集型任务,过多的协程可能会导致性能下降。
      通过使用async和await,Python程序员可以编写更加清晰和易于维护的异步代码,这对于网络应用、数据库操作和其他需要等待外部资源的场景非常有用。

    总结

    以上就是今天要讲的内容,本文仅仅简单介绍了Python中的回调函数以及异步编程。

    作者:Ronin-Lotus

    物联沃分享整理
    物联沃-IOTWORD物联网 » 程序代码篇—python回调函数&异步编程

    发表回复