同步、异步无障碍:Python异步装饰器指南

一、引言

Python异步开发已经非常流行了,一些主流的组件像MySQL、Redis、RabbitMQ等都提供了异步的客户端,再处理耗时的时候不会堵塞住主线程,不但可以提高并发能力,也能减少多线程带来的cpu上下文切换以及内存资源消耗。但在业务开发的时候一些第三方库没有异步的处理方式,例如OSS、CV、其他第三方提供的SDK以及自己封装的函数有耗时等,此时还是需要借助线程来加速,再异步中就不会堵塞主线程,因此封装一个异步装饰器可以更好的处理异步,让代码更简洁。

常用组件异步库

序号组件名异步库说明
1MySQLaiomysql github.com/aio-libs/ai…
SQLAIchemy github.com/sqlalchemy/…
tortoise-orm github.com/tortoise/to…aiomysql 基于asyncio的MySQL驱动,用asyncio实现异步IO。这是最常用的Python异步MySQL驱动。
SQLAIchemy 和 Tortoise-ORM 都是支持异步的ORM
2Redisaioredis github.com/aio-libs-ab…aioredis因为性能好、使用广泛,是Python最主流的Redis异步驱动之一。 之前同步库的redis.py 后面再4.2.0rc1+版本也支持aioredis
3RabbitMQaio-pika github.com/mosquito/ai…
celery github.com/celery/cele…基于asyncio的RabbitMQ异步客户端,是最常用的Python异步RabbitMQ客户端之一。 celery是分布式任务队列框架,也支持常用消息中间件的异步封装
4Kafkaaio-kafka github.com/aio-libs/ai…kafka常用的异步客户端
5http客户端httpx github.com/encode/http…
aiohttp github.com/aio-libs/ai…httpx一个现代的异步HTTP客户端,支持asyncio和操作语法与 Requests 库的API一致。 aiohttp也是十分常用的异步客户端,性能也不错
6文件处理aiofiles github.com/Tinche/aiof…基于asyncio的异步文件操作库,提供类文件对象接口

这里就简单列举一些常用的异步库,可以发现好多异步库都在 github 的 aio-libs 中慢慢孵化,质量都挺不错的。大家有什么好用的异步库欢迎评论区推荐。

github.com/aio-libs

二、功能分析

  1. 支持同步函数使用线程加速

  2. 异、同步函数需支持 await 语法等待返回结果

  3. 异、同步函数需支持后台任务,无需等待

同步函数使用线程加速

同步函数使用线程,这还是挺简单的使用,内置库的 threading.Thread 就可以实现

import time
import threading

def task1(name):
    print(f"Hello {name}")
    time.sleep(1)
    print(f"Completed {name}")


t1 = threading.Thread(target=task1, args=("hui",))
t2 = threading.Thread(target=task1, args=("wang",))

t1.start()
t2.start()

t1.join()
t2.join()

>>> out
Hello hui
Hello wang
Completed hui
Completed wang

  • start()方法用于启动线程执行函数。
  • join()方法用于等待线程执行结束。

但这样直接开线程的方式比较暴力,也不太好管理,因此可以想到线程池,进行线程复用与管理。Python内置的 concurrent.futures 模块提供了线程池和进程池的实现与封装。

import time
from concurrent.futures import ThreadPoolExecutor

def task2(name):
    print(f"Hello {name}")
    time.sleep(1)
    return f"Completed {name}"

with ThreadPoolExecutor(max_workers=2) as executor:
    future1 = executor.submit(task2, "hui")
    future2 = executor.submit(task2, "zack")

print("ret1", future1.result())
print("ret2", future2.result())

>>> out
Hello hui
Hello zack
ret1 Completed hui
ret2 Completed zack

异、同步函数需支持 await 语法

异、同步函数需支持 await 语法等待返回结果,异步函数本身就支持 await语法,这里主要是实现同步函数支持

await 语法,在python中可以await语法的对象有如下几大类:

  1. 协程对象(coroutine):定义了__await__方法的对象,异步框架中的协程函数都是此类型。
  2. 任务对象(Task):封装了协程的对象, 如 asyncio 中的 Task, trio中的Task。
  3. Future对象:表示异步操作结果的对象, 如 concurrent.futures.Future。
  4. 协程装饰器封装的对象:一些装饰器可以将普通函数或对象包装成可await的对象,如@asyncio.coroutine。

综上,凡是实现了__await__魔术方法的对象或者封装了协程/任务的对象,都可以被await,await会自动把对象交给事件循环运行,等待其完成。

常见的可await对象包括协程函数、任务对象、Future、被@coroutine装饰的函数等,这可以使异步代码更简洁。await对象可以暂停当前协程,等待异步操作完成后再继续执行。

import asyncio

async def coro_demo():
    print("await coroutine demo")

async def task_demo():
    print("await task demo")

    async def coro():
        print("in coro task")

    # 创建 Task 对象
    task = asyncio.create_task(coro())
    await task

async def future_demo():
    print("await future demo")
    future = asyncio.Future()
    await future

# 这个装饰器已经过时
@asyncio.coroutine
def coro_decorated_demo():
    print("await decorated function demo")

async def main():
    await coro_demo()

    await task_demo()

    await future_demo()

    await coro_decorated_demo()

if __name__ == '__main__':
    asyncio.run(main())
    
    
>>> out 
DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
  def coro_decorated_demo():
  
await coroutine demo
await task demo
in coro task
await future demo

这个 @asyncio.coroutine 协程装饰器已经过时了,都是使用 async、await 语法替代。

下面是实现 __await__ 方法的demo

import asyncio

class AsyncDownloader:

    def __init__(self, url):
        self.url = url
        self.download_ret = None

    def __await__(self):
        print(f'Starting download of {self.url}')
        loop = asyncio.get_event_loop()
        future = loop.run_in_executor(None, self.download)
        yield from future.__await__()
        return self

    def download(self):
        print(f'Downloading {self.url}...')
        # 模拟下载过程
        import time
        time.sleep(2)
        self.download_ret = f'{self.url} downloaded ok'

async def main():
    print('Creating downloader...')
    downloader = AsyncDownloader('https://www.ithui.top/file.zip')
    print('Waiting for download...')
    downloader_obj = await downloader
    print(f'Download result: {downloader_obj.download_ret}')

if __name__ == '__main__':
    asyncio.run(main())
    

>>> out
Creating downloader...
Waiting for download...
Starting download of https://www.ithui.top/file.zip
Downloading https://www.ithui.top/file.zip...
Download result: https://www.ithui.top/file.zip downloaded ok    

用 yield from 来迭代 future对象(符合__await__逻辑),并在结束时return self

异、同步函数需支持后台任务

异步、后台任务的好处与场景

  1. 减少主程序的等待时间

    异步函数可以通过后台任务的方式执行一些耗时操作,如IO操作、网络请求等,而主程序无需等待这些操作完成,可以继续执行其他任务,从而减少程序总体的等待时间。

  2. 提高程序响应性能

    后台任务的异步执行,可以避免主程序被长时间阻塞,从而改善程序的整体响应性能。用户无需长时间等待才能得到响应。

  3. 解决IO密集型任务阻塞问题

    对于网络、文件IO等密集型任务,使用同步执行可能会导致长时间阻塞,而异步后台任务可以很好地解决这个问题,避免资源浪费。

  4. 良好的用户体验

    后台任务的异步处理,给用户的感觉是多个任务同时在执行,实际上CPU在切换处理,这相比线性等待任务完成,可以提供更好的用户体验。

  5. 适用于不需要实时结果的任务

    邮件发送、数据批处理、文件处理等不需要用户即时等待结果的任务非常适合通过异步方式在后台完成。

在python中同异步函数实现后台任务

  • 异步函数可以通过 asyncio.create_task 方法实现后台任务

  • 同步函数可以通过线程、线程池来实现

import asyncio
import time
from threading import Thread
from concurrent.futures import ThreadPoolExecutor

async def async_bg_task():
    print('async bg task running')
    await asyncio.sleep(3)
    print('async bg task completed')

def sync_bg_task():
    print('sync bg task running')
    time.sleep(3)
    print('sync bg task completed')

async def main():
    print('Starting main program')

    # 异步函数的后台任务
    asyncio.create_task(async_bg_task())

    # 同步函数的后台任务
    # with ThreadPoolExecutor() as executor:
    #     executor.submit(sync_bg_task)

    # Thread(target=sync_bg_task).start()

    loop = asyncio.get_running_loop()
    loop.run_in_executor(executor=ThreadPoolExecutor(), func=sync_bg_task)

    print('Main program continues')
    await asyncio.sleep(5)

if __name__ == '__main__':
    asyncio.run(main())
    
   
>>> ThreadPoolExecutor out
Starting main program
sync bg task running
sync bg task completed
Main program continues
async bg task running
async bg task completed

>>> Thread out
Starting main program
sync bg task running
Main program continues
async bg task running
sync bg task completed
async bg task completed

>>> run_in_executor out
Starting main program
sync bg task running
Main program continues
async bg task running
async bg task completed
sync bg task completed

看输出结果可以发现在同步函数使用直接使用线程池 ThreadPoolExecutor 执行还是堵塞了主线程,然后 Thread 没有,通过 loop.run_in_executor 也不会阻塞。后面发现 是 with 语法导致的堵塞,with 的根本原因就是它会等待线程池内的所有线程任务完成并回收,所以主线程必须等同步函数结束后才能继续。一开始我还一以为是线程池使用了主线程的线程后面打印线程名称看了下不是,然后调试下就发现了with的问题。

import asyncio
import time
import threading
from concurrent.futures import ThreadPoolExecutor

async def async_bg_task():
    print(f"async_bg_task In thread: {threading.current_thread().name}")

    print('async bg task running')
    await asyncio.sleep(3)
    print('async bg task completed')

def sync_bg_task(num):
    print(f"sync_bg_task{num} In thread: {threading.current_thread().name}")

    print(f'sync bg task{num} running')
    time.sleep(3)
    print(f'sync bg task{num} completed')

async def main():
    print('Starting main program')

    # 异步函数的后台任务
    asyncio.create_task(async_bg_task())

    # 同步函数的后台任务
    thread_pool = ThreadPoolExecutor()
    # with thread_pool as pool:
    #     for i in range(5):
    #         pool.submit(sync_bg_task, i)

    for i in range(5):
        thread_pool.submit(sync_bg_task, i)

    threading.Thread(target=sync_bg_task, args=["thread"]).start()

    loop = asyncio.get_running_loop()
    loop.run_in_executor(ThreadPoolExecutor(), sync_bg_task, "loop.run_in_executor")

    print('Main program continues')
    print(f"Main program In thread: {threading.current_thread().name}")
    await asyncio.sleep(5)

if __name__ == '__main__':
    asyncio.run(main())

三、具体封装实现

import asyncio
from concurrent.futures import ThreadPoolExecutor, Executor

def run_on_executor(executor: Executor = None, background: bool = False):
    """
    异步装饰器
    - 支持同步函数使用 executor 加速
    - 异步函数和同步函数都可以使用 `await` 语法等待返回结果
    - 异步函数和同步函数都支持后台任务,无需等待
    Args:
        executor: 函数执行器, 装饰同步函数的时候使用
        background: 是否后台执行,默认False

    Returns:
    """

    def _run_on_executor(func):
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs):
            if background:
                return asyncio.create_task(func(*args, **kwargs))
            else:
                return await func(*args, **kwargs)

        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs):
            loop = asyncio.get_event_loop()
            task_func = functools.partial(func, *args, **kwargs)    # 支持关键字参数
            return loop.run_in_executor(executor, task_func)

        # 异步函数判断
        wrapper_func = async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapper
        return wrapper_func

    return _run_on_executor

封装成了带参数的装饰器

  • executor: 函数执行器, 装饰同步函数的时候使用

    • 可以传递指定的线程池,默认None 根据系统cpu核心数动态创建线程的数量
  • background: 用于标识是否后台执行,默认False

    • 有点诟病同步函数的后台任务没有用到这个参数而是使用 await 语法控制,但在使用装饰器时候可以起到后台任务标识作用,别人一看有这个参数就知道是后台任务就不用细看函数业务逻辑
    • 后续再看看怎么优化,大家有没有比较好建议
  • loop.run_in_executor(executor, task_func) 方法不支持关键字参数的传递,故而采用 task_func = functools.partial(func, *args, **kwargs) ,来构造一个不带参数的函数就可以方便使用了

测试demo

import asyncio
import time
from concurrent.futures import ThreadPoolExecutor

from py_tools.decorators.base import run_on_executor
from loguru import logger

thread_executor = ThreadPoolExecutor(max_workers=3)

@run_on_executor(background=True)
async def async_func_bg_task():
    logger.debug("async_func_bg_task start")
    await asyncio.sleep(1)
    logger.debug("async_func_bg_task running")
    await asyncio.sleep(1)
    logger.debug("async_func_bg_task end")
    return "async_func_bg_task ret end"

@run_on_executor()
async def async_func():
    logger.debug("async_func start")
    await asyncio.sleep(1)
    logger.debug("async_func running")
    await asyncio.sleep(1)
    return "async_func ret end"

@run_on_executor(background=True, executor=thread_executor)
def sync_func_bg_task():
    logger.debug("sync_func_bg_task start")
    time.sleep(1)
    logger.debug("sync_func_bg_task running")
    time.sleep(1)
    logger.debug("sync_func_bg_task end")
    return "sync_func_bg_task end"

@run_on_executor()
def sync_func():
    logger.debug("sync_func start")
    time.sleep(1)
    logger.debug("sync_func running")
    time.sleep(1)
    return "sync_func ret end"

async def main():
    ret = await async_func()
    logger.debug(ret)

    async_bg_task = await async_func_bg_task()
    logger.debug(f"async bg task {async_bg_task}")
    logger.debug("async_func_bg_task 等待后台执行中")

    loop = asyncio.get_event_loop()
    for i in range(3):
        loop.create_task(async_func())

    ret = await sync_func()
    logger.debug(ret)

    sync_bg_task = sync_func_bg_task()
    logger.debug(f"sync bg task {sync_bg_task}")
    logger.debug("sync_func_bg_task 等待后台执行")

    await asyncio.sleep(10)

if __name__ == '__main__':
    asyncio.run(main())

测试详细输出

async_func start
async_func running
async_func ret end

async bg task <Task pending name='Task-2' coro=<async_func_bg_task() running at ...
sync_func start
async_func_bg_task start
async_func start
async_func start
async_func start

sync_func running
async_func_bg_task running
async_func running
async_func running
async_func running

async_func_bg_task end
sync_func ret end

sync_func_bg_task start
sync bg task <Future pending cb=[_chain_future.<locals>._call_check_cancel() at ...
sync_func_bg_task 等待后台执行
sync_func_bg_task running
sync_func_bg_task end

如果你对Python感兴趣,想要学习python,这里给大家分享一份Python全套学习资料,都是我自己学习时整理的,希望可以帮到你,一起加油!

😝有需要的小伙伴,可以V扫描下方二维码免费领取🆓

1️⃣零基础入门

① 学习路线

对于从来没有接触过Python的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
在这里插入图片描述

② 路线对应学习视频

还有很多适合0基础入门的学习视频,有了这些视频,轻轻松松上手Python~
在这里插入图片描述

③练习题

每节视频课后,都有对应的练习题哦,可以检验学习成果哈哈!
在这里插入图片描述

2️⃣国内外Python书籍、文档

① 文档和书籍资料

在这里插入图片描述

3️⃣Python工具包+项目源码合集

①Python工具包

学习Python常用的开发软件都在这里了!每个都有详细的安装教程,保证你可以安装成功哦!
在这里插入图片描述

②Python实战案例

光学理论是没用的,要学会跟着一起敲代码,动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。100+实战案例源码等你来拿!
在这里插入图片描述

③Python小游戏源码

如果觉得上面的实战案例有点枯燥,可以试试自己用Python编写小游戏,让你的学习过程中增添一点趣味!
在这里插入图片描述

4️⃣Python面试题

我们学会了Python之后,有了技能就可以出去找工作啦!下面这些面试题是都来自阿里、腾讯、字节等一线互联网大厂,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
在这里插入图片描述
在这里插入图片描述

上述所有资料 ⚡️ ,朋友们如果有需要的,可以扫描下方👇👇👇二维码免费领取🆓

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023一带一路暨金砖国家技能发展与技术创新大赛“网络安全”赛项省选拔赛样题卷①

2023金砖国家职业技能竞赛"网络安全" 赛项省赛选拔赛样题 2023金砖国家职业技能竞赛 省赛选拔赛样题第一阶段&#xff1a;职业素养与理论技能项目1. 职业素养项目2. 网络安全项目3. 安全运营 第二阶段&#xff1a;安全运营项目1. 操作系统安全配置与加固任务一Linux …

基于信号完整性的一些PCB设计建议

最小化单根信号线质量的一些PCB设计建议 1. 使用受控阻抗线&#xff1b; 2. 理想情况下&#xff0c;所有信号都应该使用完整的电源或地平面作为其返回路径&#xff0c;关键信号则使用地平面作为返回路径&#xff1b; 3. 信号的返回参考面发生变化时&#xff0c;在尽可能接近…

欧盟产品安全新规来袭,亚马逊发出紧急提醒(GPSR)要求

欧盟产品安全新规来袭&#xff0c;亚马逊发出紧急提醒&#xff08;GPSR&#xff09;要求 一、发布新规 这世界上唯一不变的事&#xff0c;或许就是变化本身。 在跨境电商领域&#xff0c;这个道理再次得到验证。近日&#xff0c;不少卖家都收到了一封来自亚马逊的通知。通知中…

springboot下载图片的简单处理方式

参考地址 springboot&#xff1a;各种下载文件的方式_springboot下载文件-CSDN博客 开箱即用实战 GetMapping("/t1")public void down1(HttpServletResponse response) throws Exception {response.reset();response.setContentType("application/octet-strea…

在服务器上使用Docker运行SRS Stack,推拉直播流、多平台转播、本地录制、虚拟直播、直播转码、AI字幕、其他

SRS Stack | SRS (ossrs.net) Docker​ 推荐使用Docker运行SRS Stack&#xff1a; docker run --restart always -d -it --name srs-stack -v $HOME/data:/data \-p 2022:2022 -p 2443:2443 -p 1935:1935 -p 8000:8000/udp -p 10080:10080/udp \registry.cn-hangzhou.aliyun…

Linux 多个php版本选择需要的php的版本(修改环境变量)

这两天遇到了个问题&#xff0c; 原本服务器的php版本是7.3.13&#xff0c;经过一些操作之后不知道怎么了变成了5.6 #php版本查看 php -v然后我就对 5.6版本进行了升级&#xff0c;升级到了7.3.33&#xff0c; 这个时候 php -v 是7.3.33&#xff0c; 神奇的一幕出现了&#xf…

把握现货黄金的基本操作技巧

在投资市场这个大舞台上&#xff0c;有各种各样的投资产品供投资者选择&#xff0c;其中黄金作为一种重要的投资资产&#xff0c;一直受到广大投资者的青睐。然而&#xff0c;黄金交易并非易事&#xff0c;需要掌握一定的操作技巧。那么&#xff0c;如何才能把握住现货黄金的操…

XS2180四通道,兼容 IEEE 802.3at/af以太网供电 PSE 控制器 V1.0

XS2180 是一个四通道、供电设备&#xff08; PSE &#xff09;电源控制 器&#xff0c;设计用于 IEEE 802.3at/af 兼容 PSE 。器件提供用 电设备&#xff08; PD &#xff09;检测、分级、限流以及负载断开检测。器 件支持自动工作和软件编程。器件还支持最新二事件分…

删除运行框中的文件打开历史记录

当我们使用everything、百度、迅雷等软件&#xff0c;在列表中右键选中打开文件夹时。 当使用 winR 快捷键等方式打开运行时&#xff0c;输入盘符会出现之前打开过的文件夹&#xff0c; 一方面展示的特别多会比较混乱&#xff0c;另一方面 记得在之前的window版本中&#xff08…

数据库系列:InnoDB下实现高并发控制

1 介绍 并发控制是为了防止多用户并发使用数据库时造成数据错误和程序运行错误&#xff0c;保证数据的完整性。当多个事务并发地存取数据库时&#xff0c;就会产生同时读取和/或修改同一数据的情况。若对并发操作不加控制就可能会存取和存储不正确的数据&#xff0c;破坏数据库…

第27集《佛法修学概要》

丁二、天乘分三&#xff1a;戊一、十善业。戊二、四禅定。戊三、四空定 请大家打开讲义第七十七页&#xff0c;这是五乘里面的第二个法门&#xff0c;天乘法门。 大乘佛教把我们众生生命的现象分成了三个部分&#xff1a;第一个部分&#xff0c;叫作 本来清净&#xff1b;第…

CSS 之 跑马灯边框

一、简介 ​ 之前有做过渐变色边框的样式&#xff0c;然后某天刷抖&#x1f3b5;&#xff0c;看到某个老师在讲跑马灯的样式效果&#xff0c;于是就自己尝试实现一下跑马灯样式的边框&#xff0c;虽然这种样式并不常见&#xff08;基本没卵用&#xff09;&#xff0c;其使用场…

git的分支的使用,创建分支,合并分支,删除分支,合并冲突,分支管理策略,bug分支,强制删除分支

GIT | 分支 文章目录 GIT | 分支创建分支合并分支删除分支合并冲突分支管理策略bug分支强制删除分支 创建分支 查看当前本地仓库中有哪些分支 git branchHEAD所指向的分支就是当前正在工作的分支 cat .git/HEAD创建一个分支 git branch dev创建好了&#xff0c;但是目前还是…

Redis基础系列-哨兵模式

Redis基础系列-哨兵模式 文章目录 Redis基础系列-哨兵模式1. 引言2. 什么是哨兵模式&#xff1f;3. 哨兵模式的配置4. 哨兵模式的启动和验证4.1 主master宕机&#xff0c;看会出现什么问题4.2 重启6379主机 5. 哨兵模式的工作原理和选举原理5.1. SDown主观下线&#xff08;Subj…

Vue.js轻量级框架:快速搭建可扩展的管理系统

一、前言 在项目实战开发中&#xff0c;尤其是大平台系统的搭建&#xff0c;针对不同业务场景&#xff0c;需要为用户多次编写用于录入、修改、展示操作的相应表单页面。一旦表单需求过多&#xff0c;对于开发人员来说&#xff0c;算是一种重复开发&#xff0c;甚至是繁杂的工作…

RFID技术在汽车装备中的应用:提升安全性与效率

RFID技术在汽车装备中的应用&#xff1a;提升安全性与效率 射频识别&#xff08;RFID&#xff09;技术是一种非接触式的自动识别技术&#xff0c;它利用射频信号及其空间耦合和传输特性&#xff0c;实现对目标对象的信息读写。随着汽车工业的不断发展&#xff0c;汽车装备的技…

开源28181协议视频平台搭建流程

最近项目中用到流媒体平台&#xff0c;java平台负责信令部分&#xff0c;c平台负责流媒体处理&#xff0c;找了评分比较好的开源项目 https://gitee.com/pan648540858/wvp-GB28181-pro 流媒体服务基于 c写的 https://github.com/ZLMediaKit/ZLMediaKit 说明文档&#xff1a;h…

ElasticSearch扫盲概念篇[ES系列] - 第500篇

历史文章&#xff08;文章累计500&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 E…

laravel异步消息队列详细攻略Supervisor队列进程管理(实战)

1、laravel配置开启队列 这里仅演示数据库队列 查看下面/config/queue.php&#xff0c;里面defult 对应的 env常量是 QUEUE_DRIVER&#xff0c;那就在 项目根目录下的.env文件修改 QUEUE_DRIVERdatabase <?phpreturn [/*|----------------------------------------------…

64位ATT汇编语言学习第一课:汇编和链接

源文件exitTest.s内容如下&#xff1a; # This is the first program .global _start .section .text _start:movq $60,%raxmovq $9,%rdisyscall源文件里边放的就是源代码&#xff0c;而我这里源代码是使用汇编语言写的&#xff0c;都是一些人类都可以阅读的字符。之后需要经过…