当前位置: 首页 > news >正文

【Linux】进程状态|僵尸进程|孤儿进程

前言

本文继续深入讲解进程内容——进程状态。
一个进程包含有多种状态,有运行状态,阻塞状态,挂起状态,僵尸状态,死亡状态等等,其中,阻塞状态还包含深度睡眠和浅度睡眠状态。

在这里插入图片描述
在这里插入图片描述

个人主页:🍝在肯德基吃麻辣烫
我的gitee:Linux仓库
个人专栏:Linux专栏
分享一句喜欢的话:热烈的火焰,冰封在最沉默的火山深处

文章目录

  • 前言
  • 进程状态
    • 1.运行状态(R状态)
    • 2. 阻塞状态(S状态)
      • 2.1 浅度睡眠状态(S状态)
        • 前台进程和后台进程
      • 2.2深度睡眠状态(D状态)
    • 3.挂起状态(无需暴露给用户)
    • 4.僵尸进程(Z状态)
      • 僵尸进程的危害
    • 5.孤儿进程
  • 总结



进程状态

我们人无时无刻都处在不同的状态,可能这时候在学习,那就是学习状态,学完了去睡觉,那就是休息状态。进程也是有多种状态,下面来一一讲解。

在Linux内核源代码中,进程的几种状态如下:

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

1.运行状态(R状态)

操作系统在对众多进程进行管理时,往往会建立一些数据结构来进行管理,在操作系统中,这个数据结构就是队列 + 双链表

在这里插入图片描述

调度器所管理的数据结构叫做运行队列

其中,这个运行队列对应的结构体为:

struct RunQueue
{struct task_struct *head;struct task_struct *tail;
};

实际上,进入运行队列排队的不是进程的代码和数据在排队,而是PCB数据结构在排队,因为PCB本身就是一个数据结构, 里面有各种指针,可以链接起来。

所以,运行队列的head指针直接指向第一个PCB对象,tail指针指向最后一个PCB对象即可完成队列的排队。

在这里插入图片描述
前面说过一个概念叫做调度器,这个调度器其实就是一个函数,可以接收一些进程的参数来获取运行队列中有多少个进程在排队等信息。

所以,我们把在运行队列中的进程状态叫做运行态,即R状态

这里有个问题,为什么在运行队列的进程就是R状态,而不是被CPU调度运行的进程才是R状态吗?

我们知道,一个进程既然已经在运行队列中排队等待了,那就说明该进程已经准备好了!所以,在该运行队列排队的进程,就是处于R状态

将来如果一个新的进程想要被调度运行,它只需要进入运行队列中排队等待,CPU会根据排队顺序一个个地运行,所以,在运行队列的进程状态就是运行态

这里还有第二个问题,一个进程被放到CPU上面运行,是不是要等到进程运行完之后才被放下来?

很显然不是。因为如果我写了一个死循环,被CPU调度运行起来,那岂不是我整个电脑的其他程序都得等到循环结束才能运行其他进程?死循环是不会结束的。

根据生活经验来看,我们执行一个死循环,其他程序一样会正常跑起来。

这是因为每个进程都有它执行的时间片

这个时间片是一个进程会被放到CPU上调度执行的时间
假如一个进程的时间片是10ms,那不管这个进程是不是死循环,它只能跑最多10ms就会被弹出来,到下一个进程被CPU调度运行。

所以,只要有了这个时间片的概念,死循环就不会一直被执行,就没有一个进程过长时间占用一个CPU的情况出现了。

注意:一个CPU,只有一个运行队列。

2. 阻塞状态(S状态)

2.1 浅度睡眠状态(S状态)

在操作系统内部,OS对各种外设进行管理时,因为一切外设都是文件,所以操作系统对外设进行管理同样是先描述,再组织。操作系统对外设管理时,先将外设描述起来,就形成一个个task_struct结构体,然后再进行组织,这个组织的过程,就是将各种PCB结构体连接起来形成链表
在这里插入图片描述

我们知道,一个进程是由PCB数据结构对象和该进程所对应的数据和代码组成的。
所以在进程的PCB结构体内部会有它所包含的各种指针信息,这些指针信息会指向外设所对应的等待队列中。

  • 而对于一个进程来讲,它可能会需要从外设读取数据,也就是从键盘,硬盘等外设获取信息。假如一个进程需要等待键盘输入数据,而键盘一直不输入,那么该进程就会被放到键盘所对应的等待队列中。

因为这个时候,这个进程一定是没有准备好的!

  • 注意:每一个外设都会有对应的等待队列,就连进程之间,也会有各种等待队列。

一个外设可能会有多个进程在排队等待从该外设中获取数据。这些进程会在该外设的等待队列中排队等待,如下图:在这里插入图片描述

如果一个进程想要从硬盘获取数据,又想从键盘获取数据,那么它可能需要在几个等待队列中进行排队。

所以,我们把这种在等待队列中排队的进程对应的状态叫做阻塞状态(S状态),也叫做浅度睡眠状态

如果一个进程处于阻塞状态,即正在等待数据到位,当我们从键盘中输入数据时,该进程所获取的数据就达到了,此时CPU就会将该进程唤醒,并将该进程从等待队列放到运行队列中,即从S状态变成R状态

阻塞状态的本质就是等待某种资源就绪。

综合运行状态和阻塞状态来看,进程之间的各种状态,无非就是将进程从一个队列放到另一个队列中罢了。

  • 注意:上面所有运行队列,等待队列,实际上都是进程的PCB在排队。

下面给一个例子感受一下S状态和R状态的问题:

code.c1 #include<stdio.h>2 #include<unistd.h>3 4 int main()5 {6     while(1)7     {                                                                                                                                   8     }9     return 0;10 }

当我们创建一个code.c文件,编译运行上面的代码后,然后查看进程的状态,结果如下:
在这里插入图片描述
为什么code程序会是S状态?
它可是一直在显示屏中每隔1秒打印一次。

这是因为我们的CPU运行速度实在是太快了,一个进程被放到运行队列等待的时间加上运行时间都比显示器文件资源准备就绪时间还要很多。导致显示器的显式跟不上CPU调度进程,导致进程有99%以上的时间处于阻塞状态,也就是在等待显示器资源准备就绪,只有不到%1的时间处于运行状态

前台进程和后台进程

细心的你会发现,我们说的S状态,在上面的例子中,并不是S状态,而是S+状态,S+状态和S状态的区别是:

  • S+状态是处于前台进程,S状态是处于后台进程

前台进程是指:在我们肉眼可见的地方运行该程序,我们可以对该程序进行中止。在这里插入图片描述
比如按下ctrl + c,就可以让该循环终止,这个就叫前台进程

而后台进程是无法通过ctrl + c,或者ctrl + d操作进行终止的。
我们只需要执行./code &加上一个取地址符号即可让该进程处于后台运行状态。
如果想要终止后台进程,则需要通过kill指令杀掉该进程。

kill -9 + 对应进程的pid

即可杀掉后台进程。

  • 注意:上面说的浅度睡眠状态,是可以被唤醒的。
  • 下面所说的深度睡眠状态,无法被唤醒。

2.2深度睡眠状态(D状态)

下面以一个小故事来帮助理解:

假如一个进程,它有1GB数据要写入磁盘中,进程说:磁盘啊,你帮我把这1GB数据放进你那里。磁盘慢悠悠地看了一下说:好的,等我一下。然后这个进程,就坐在那里慢悠悠地等着,(因为磁盘的写入速度是比较慢的)此时,操作系统不知道因为什么原因,突然出现大量进程占用CPU资源,内存资源极度匮乏,操作系统为了补救把能换出的数据全都换出了,还是没多大效果。然后操作系统看到了进程这货在这满面春风,心里气不打一处来,对着进程说:我这里都火上浇油了,你还有心思搁这喝茶??还没来得及等进程解释,这个进程就直接被操作系统干掉了,来缓解内存压力。然后操作系统就走了,等到磁盘把数据写完,慢悠悠地过来想告诉进程时,发现进程不见了,找都找不到。无奈,磁盘不知道怎么处理那1GB数据,毕竟后面还有那么多进程排队等着我去写入数据呢,所以磁盘只能把这1GB数据给丢了。可它却不知道,这1GB数据是银行里面各种百万级别用户存的资金!

在这里插入图片描述

为了防止再出现上面的悲剧,程序员只能想出一个办法,当进程在等待磁盘写入数据时,**不能让任何人打扰到进程的等待,即让进程处于D状态!**包括操作系统在内!这样做就能够让进程等待直到获取到磁盘的反馈结果!

这就相当于进程得到免死金牌一样了。

那如果有多个进程都处于D状态呢?

实际上,只要有一个进程处于D状态,操作系统就在处于崩溃的边缘了。如果有两三个D状态,操作系统基本上就完了。

3.挂起状态(无需暴露给用户)

在平常使用电脑时,可能会有这样一种情况:操作系统内存严重不足这样的情况可能会发送在我们打开了大量的软件,并且这些软件都是大量占用CPU资源的。

这些进程的数据和代码量庞大,是占用CPU资源的主要因素,所以操作系统想出了一个办法:既然这些进程在运行队列,等待队列中排队都是该进程的PCB对象在排队,那它们对应的数据和代码为何不放在硬盘中,等到该进程被调度时,再把该进程对应的数据和代码从硬盘中拿出来呢?

这样做我们就能缓解操作系统内存严重不足的情况。
其中:
进程的数据和代码被放到硬盘这个过程叫做换出

从硬盘中读取回到操作系统的过程叫做换入

所以,只有进程的PCB在队列中排队,该进程的数据和代码被放在硬盘中的这个状态叫做挂起状态

4.僵尸进程(Z状态)

这个进程状态听起来还比较吓人,它具体的意思是:

  • 当一个子进程退出程序后,父进程如果不关心子进程,也就是父进程没有回收子进程的空间,资源等。子进程就会处于僵尸状态,即Z状态
  • 僵尸进程会以终止状态保存在进程表中,并一直等待父进程读取它的退出返回码。

下面有一个例子:

  1 #include<stdio.h>2 #include<unistd.h>3 4 int main()5 {6     //父进程7     pid_t id = fork();8     if(id > 0)9     {10         int cnt = 100;11         while(cnt--)12         {13             printf("我是父进程,我的pid是%d,我的ppid是%d\n",getpid(),getppid());14             sleep(1);15         }16     }17     //子进程18     else if(id == 0)19     {                                                           20         int cnt = 5;21         while(cnt--)22         {23             printf("我是子进程,我的pid是%d,我的ppid是%d\n",getpid(),getppid());24             sleep(1);25         }26     }27     return 0;28 }

在这里插入图片描述

通过上面代码及运行结果可知,当子进程没有退出时,父子进程都处于S状态,这个好理解,因为父进程要等到显示器资源就绪,它才会从等待队列被放到运行队列中,(时间极短,无法展示)当子进程退出程序时,处于Z状态。
这是因为当子进程退出时,父进程没有对子进程的资源进行回收释放,不关心子进程。

接下来就必须说到僵尸进程的危害了。

僵尸进程的危害

  • 子进程是被父进程创建出来的,自然要执行一些父进程交代的任务,可如果子进程退出了,它就必须把任务执行得怎么样了反馈给父进程,所以它会一直维持退出状态,等待父进程来读取,如果父进程不来读取,子进程一直处于Z状态。维持一个进程是需要消耗内存资源的,一个进程维持在某种状态,本质上是该进程的PCB数据结构在某个队列中排队等待!这就要一直维护该进程的PCB!
  • 所以,如果一个父进程创建了大量子进程,并且都不回收,那这些子进程都会处于Z状态它们的PCB数据结构一直在一个队列中排队等待,意味着它们一直在吃内存资源,就会造成内存泄露!

那为什么父进程退出时没有处于Z状态?

  • 因为父进程的父亲是bash进程,父进程一退出,bash进程就立刻对父进程回收了。
    由于每个进程只会对父进程负责,这个父进程的子进程跟bash进程并没有关系,也就是爷爷进程和孙子进程没啥关系,所以就无法让bash进程也回收孙子进程。

  • 另一个原因是孙子进程并不是bash进程创建的,它没有能力对孙子进程回收。


5.孤儿进程

孤儿进程相对于僵尸进程类似,孤儿进程是:

  • 如果父进程先退出,那子进程就没有父亲了,子进程就是一个孤儿进程!

孤儿进程重点:

如果父进程先退出了,子进程的父进程的ppid会立刻变成1号进程,即操作系统
意思就是:父进程退出后,子进程会被操作系统领养!


为什么操作系统要领养子进程呢?

因为以后子进程也要退出,也需要被回收,让操作系统回收最合适不过。


让bash进程回收子进程不行吗?

bash进程只能回收它的子进程,没办法回收孙子进程。

总结

本文章讲述了进程的几个基本状态:运行状态,阻塞状态(深度睡眠状态和浅度睡眠状态),挂起状态,僵尸状态等。以及两个比较重要的进程:僵尸进程和孤儿进程。
到目前为止,所具备的知识还无法解决僵尸进程和孤儿进程的问题,到后面会解决。

进程状态切换的本质是一个进程的PCB从一个队列被放到另一个队列中排队。

本文到这里就结束啦。

相关文章:

【Linux】进程状态|僵尸进程|孤儿进程

前言 本文继续深入讲解进程内容——进程状态。 一个进程包含有多种状态&#xff0c;有运行状态&#xff0c;阻塞状态&#xff0c;挂起状态&#xff0c;僵尸状态&#xff0c;死亡状态等等&#xff0c;其中&#xff0c;阻塞状态还包含深度睡眠和浅度睡眠状态。 个人主页&#xff…...

ASEMI快恢复二极管APT80DQ60BG特点应用

编辑-Z APT80DQ60BG参数描述&#xff1a; 型号&#xff1a;APT80DQ60BG 最大峰值反向电压(VRRM)&#xff1a;600V 最大直流阻断电压VR(DC)&#xff1a;600V 平均整流正向电流(IF)&#xff1a;80A 非重复峰值浪涌电流(IFSM)&#xff1a;600A 工作接点温度和储存温度(TJ, …...

【Python爬虫】使用代理ip进行网站爬取

前言 使用代理IP进行网站爬取可以有效地隐藏你的真实IP地址&#xff0c;让网站难以追踪你的访问行为。本文将介绍Python如何使用代理IP进行网站爬取的实现&#xff0c;包括代理IP的获取、代理IP的验证、以及如何把代理IP应用到爬虫代码中。 1. 使用代理IP的好处 在进行网站爬…...

识别图片中的文字

前言 PearOCR 是一款免费无限制网页版文字识别工具。 优点如下&#xff1a; 免费&#xff1a;完全免费&#xff0c;没有任何次数、大小限制&#xff0c;可以无限使用&#xff1b; 安全&#xff1a;全部数据本地运算&#xff0c;所有图片均不会被上传&#xff1b; 智能&#xf…...

第七章:借阅管理【基于Servlet+JSP的图书管理系统】

借阅管理 1. 借书卡 1.1 查询借书卡 借书卡在正常的CRUD操作的基础上&#xff0c;我们还需要注意一些特殊的情况。查询信息的时候。如果是管理员则可以查询所有的信息&#xff0c;如果是普通用户则只能查看自己的信息。这块的控制在登录的用户信息 然后就是在Dao中处理的时候需…...

算法 for GAMES

栈 #include <iostream> #include <stack>int main() {std::stack<int> intStack;// 压入元素到堆栈intStack.push(5);intStack.push(10);intStack.push(15);// 查看堆栈顶部元素std::cout << "Top element: " << intStack.top() <…...

自研分布式IM-HubuIM RFC草案

HubuIM RFC草案 消息协议设计 基本协议 评估标准 【性能】协议传输效率&#xff0c;尽可能降低端到端的延迟&#xff0c;延迟高于200ms用户侧就会有所感知 【兼容】既要向前兼容也要向后兼容 【存储】减少消息包的大小&#xff0c;降低空间占用率&#xff0c;一个字节在亿…...

tableau基础学习1:数据源与绘图

文章目录 读取数据常用绘图方法1. 柱状图2. 饼图3. 散点图4. 热力图 第一部分是一些较容易上手的内容&#xff0c;以及比较常见的可视化内容&#xff0c;包括&#xff1a;柱状图、饼图、散点图与热力图 读取数据 打开界面后&#xff0c;选择数据源之后就可以导入数据&#xf…...

探索经典算法问题与解决方案

探索经典算法问题与解决方案 在计算机科学领域&#xff0c;有许多经典算法问题需要我们思考和解决。本文将深入介绍一些著名的经典算法问题&#xff0c;包括旅行商问题、背包问题的变种、N皇后问题、钢条切割问题、最大子数组和问题、最长公共子串问题以及矩阵连乘问题&#x…...

【Linux】DNS系统,ICMP协议,NAPT技术

遏制自己内心的知识优越感&#xff0c;才能让你发自内心的去尊重他人&#xff0c;避免狂妄自大&#xff0c;才能让你不断的丰富自己的内心。 文章目录 一、DNS系统1.DNS服务器返回域名对应的ip2.使用dig工具分析DNS过程3.浏览器中输入url后发生的事情&#xff1f; 二、ICMP协议…...

BI技巧丨Window应用之同环比

白茶曾介绍过OFFSET可以用来解决同环比的问题&#xff0c;其实微软最近推出的开窗函数WINDOW也可以用来解决同环比。 WINDOW函数基础语法 WINDOW ( from[, from_type], to[, to_type][, <relation>][, <orderBy>][, <blanks>][, <partitionBy>][, &l…...

【Mac】编译Spring 源码和Idea导入

今天我们开始Spring源码的阅读之旅。阅读Spring的源码的第一步当然是编译Spring源码。首先我们要去GitHub上将spring源码给clone下来。 笔者编译环境如下&#xff1a; Spring版本&#xff1a;5.28 https://github.com/spring-projects/spring-framework/tree/v5.2.8.RELEASE …...

手把手教你用 ANSYS workbench

ANSYS Workbench ANSYS Workbench是一款基于有限元分析&#xff08;FEA&#xff09;的工程仿真软件。其基本概念包括&#xff1a; 工作区&#xff08;Workspace&#xff09;&#xff1a;工程仿真模块都在此区域内&#xff0c;包括几何建模、网格划分、边界条件设置、分析求解等…...

Kotlin开发笔记:协程基础

Kotlin开发笔记&#xff1a;协程基础 导语 本章内容与书的第十五章相关&#xff0c;主要介绍与协程相关的知识。总的来说&#xff0c;本文将会介绍Kotlin中关于异步编程的内容&#xff0c;主要就是与协程有关。在Kotlin中协程是利用continuations数据结构构建的&#xff0c;用…...

自学设计模式(简单工厂模式、工厂模式、抽象工厂模式)

使用工厂模式来生产某类对象&#xff08;代码简化且容易维护&#xff0c;类之间有血缘关系&#xff0c;可以通过工厂类进行生产&#xff09;&#xff1b; 简单工厂模式&#xff08;用于创建简单对象&#xff09; 对于简单工厂模式&#xff0c;需要的工厂类只有一个&#xff1…...

NFS:使⽤ NFS 为远程客户端提供共享文件系统

写在前面 分享一些 nfs 搭建的笔记考试顺便整理内容涉及 nfs 服务端客户端的搭建配置理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停息。所有其它的路都是不完整的&…...

2022-kaggle-nlp赛事:Feedback Prize - English Language Learning(超多注释讲解)

2022-kaggle-nlp赛事&#xff1a;Feedback Prize - English Language Learning 零、比赛介绍 比赛地址Feedback Prize - English Language Learning | Kaggle 0.1 比赛目标 写作是一项基本技能。可惜很少学生能够磨练&#xff0c;因为学校很少布置写作任务。学习英语作为第…...

第十三课 宾语从句

文章目录 前言一、宾语从句1、主语及物动词宾语从句2、主语双宾动词间接宾语直接宾语3、主语特定及物动词宾语从句&#xff08;作宾语&#xff09;宾补4、主语be某些形容词宾语从句5、动词不定式后面的宾语从句6、动名词后面的宾语从句7、介词后面的宾语从句9、间接引语 前言 一…...

Docker容器与虚拟化技术:GitHub账户注册

目录 一、实验 1.GitHub 一、实验 1.GitHub &#xff08;1&#xff09;GitHub是一个面向开源及私有软件项目的托管平台&#xff0c;因为只支持Git作为唯一的版本库格式进行托管&#xff0c;故名GitHub。 &#xff08;2&#xff09;官网 GitHub: Let’s build from here …...

thinkphp安装workman

需要加版本&#xff0c;版本太高了不行 composer require topthink/think-worker1.0.*...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...