当前位置: 首页 > 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.*...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...