C++linux高并发服务器项目实践 day7

news2025/1/9 12:56:30

C++linux高并发服务器项目实践 day7

  • 进程间通信
    • 匿名管道
    • 管道的特点
    • 匿名管道的使用
      • 创建匿名管道
      • 查看管道缓冲大小命令
      • 查看管道缓冲大小函数
      • 匿名管道通信案例
    • 管道的读写特点
  • 有名管道
    • 有名管道的使用
    • 写FIFO管道
    • 读FIFO管道
    • 总结
    • 有名管道实现简单版聊天功能

进程间通信

  • 进程是一个独立的资源分配单元,不同进程(这里所说的进程通常指的是用户进程)之间的资源是独立的,没有关联,不能再一个进程中直接访问另一个进程的资源
  • 但是,进程不是孤立的,不同的进程需要进行信息的交互和状态的传递等,因此需要进程间通信
  • 进程间通信的目的:
    • 数据传输:一个进程需要将它的数据发送给另一个进程
    • 通知事件:一个进程需要向另一个或一组进程发送消息,通知他们发生了某种事件(如进程终止时要通知父进程)
    • 资源共享:多个进程之间共享同样的资源。为了做到这一点,需要内核提供互斥和同步机制
    • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和一次,并能够及时知道它的状态改变

不同进程间通信方式

匿名管道

  • 管道也叫无名(匿名)管道,它是UNIX系统IPC(进程间通信)的最古老性形式,所有的UNIX系统都支持这种通信机制
  • 统计一个目录中文件的数目目录:ls | wc -l ,为了执行该命令,shell创建另两个进程来分别执行ls和wc

在这里插入图片描述

管道的特点

  • 管道其实是一个在内核内存中维护的缓冲器,这个缓冲器的存储能力是有限的,不同的操作系统大小不一定相同
  • 管道拥有文件的特质:读操作、写操作,匿名管道没有文件实体,有名管道有文件实体,但不存储数据。可以按照操作文件的方式对管道进行操作
  • 一个管道是一个字节流,使用管道时不存在消息或者消息边界的概念,从管道读取数据的进程可以读取任意大小的数据块,而不管写入进程写入管道的数据块的大小是多少
  • 通过管道传递的数据是顺序的,从管道中读取出来的字节的顺序和他们被写入管道的顺序是完全一样的
  • 在管道中的数据的传递方向是单向的,一端用于写入,一端用于读取,管道是半双工的。
  • 在管道读数据是一次性操作,数据一旦被读走,它就从管道中被抛弃,释放空间以便写更多的数据,在管道中无法使用lseek()来随机访问数据
  • 匿名管道只能在具有公共祖先的进程(父进程与子进程,或者两个兄弟进程,具有亲缘关系)之间使用

在这里插入图片描述
管道的数据结构是循环队列结构
在这里插入图片描述

匿名管道的使用

  • 创建匿名管道
    #include <unistd.h>
    int pipe(int pipefd[2]);
  • 查看管道缓冲大小命令
    ulimit -a
  • 查看管道缓冲大小函数
    #include <unistd.h>
    long fpathconf(int fd,int name);

创建匿名管道

#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建一个匿名管道,用来进程间通信
参数:int pipefd[2] 这个数组是一个传出参数。
pipefd[0] 对应的是管道的读端
pipefd[1] 对应的是管道的写端
返回值:
成功返回 0
失败返回 -1

管道默认是阻塞的:如果管道中没有数据,read阻塞,如果管道满了,write阻塞

注意:匿名管道只能哟弄关于具有关系的进程之间的通信(父子进程,兄弟进程)

    #include <unistd.h>
    #include <sys/types.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>


//子进程发送数据给父进程,父进程读取到数据后输出
int main(){

    //在fork之前创建管道
    int pipefd[2];
    int ret = pipe(pipefd);
    if(ret == -1){
        perror("pipe");
        exit(0);
    }

    //创建子进程
    pid_t pid = fork();
    if(pid > 0){
        //父进程
        printf("i am parent process,pid :%d\n",getpid());
        //从管道读取端读取数据
        char buf[1024] = {0};
        while(1){
            int len = read(pipefd[0],buf,sizeof(buf));
            printf("parent recv : %s,pid : %d\n",buf,getpid());

            char *str = "hello,i am parent";
            write(pipefd[1],str,strlen(str));
            sleep(1);
        }

    }else if(pid == 0){
        //子进程
        printf("i am child process,pid :%d\n",getpid());
        char buf[1024] = {0};
        while(1){
            char *str = "hello,i am child";
            write(pipefd[1],str,strlen(str));
            sleep(1);

            int len = read(pipefd[0],buf,sizeof(buf));
            printf("child recv : %s,pid : %d\n",buf,getpid());
        }

    }

    return 0;
}

查看管道缓冲大小命令

ulimit -a

输入后,可以在pipe size一行查看大小
这里显示的数值是块的多少,而块的大小在前面

查看管道缓冲大小函数

#include <unistd.h>

long fpathconf(int fd, int name);
long pathconf(const char *path, int name);


    #include <unistd.h>
    #include <sys/types.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>


int main(){

    int pipefd[2];

    int ret = pipe(pipefd);

    //获取管道的大小
    long size = fpathconf(pipefd[0],_PC_PIPE_BUF);

    printf("pipe size: %ld\n",size);

    return 0;
}

匿名管道通信案例

在这里插入图片描述
实现ps aux|grep xxx
父子进程间通信

子进程: ps aux ,子进程结束后,将数据发送给父进程

父进程:获取到数据,过滤

pipe()
execlp()
子进程将标准输出 stdout_fileno 重定向到管道的写端。dup2()

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wait.h>

int main(){

    //创建一个管道
    int fd[2];
    int ret = pipe(fd);

    if(ret == -1){
        perror("pipe");
        exit(0);
    }

    //创建子进程
    pid_t pid = fork();

    if(pid > 0){
        //父进程
        //关闭写端
        close(fd[1]);
        //从管道中读取
        char buf[1024] = {0};

        int len = -1;
        while ((len = read(fd[0],buf,sizeof(buf)-1)) >  0)
        {
            
            //过滤数据输出
            printf("%s",buf);
            memset(buf,0,1024);
        }
        wait(NULL);
        

    }else if (pid == 0)
    {
        //子进程
        //关闭读端
        close(fd[0]);

        //文件描述符的重定向 stdout_fileno -> fd[1]
        dup2(fd[1],STDOUT_FILENO);
        //执行ps aux
        execlp("ps","ps","aux",NULL);

        perror("execlp");
        exit(0);
    }else 
    {
        perror("fork");
        exit(0);
    }
    
    

    return 0;
}

管道的读写特点

使用管道时,需要注意一下几种特殊情况(假设都是阻塞I/O操作):

  1. 所有的指向管道写端的文件描述符都关闭了(管道写端引用计数为0),有进程从管道的读端读数据,那么管道中剩余的数据被读取以后,再次read会返回0,就像读到文件末尾一样
  2. 如果有指向管道写端的文件描述符没有关闭(管道的写端引用计数大于0),而持有管道写端的也没有往管道中写数据,这个时候有进程从管道中读取数据,那么管道中剩余的数据被读取后,我们再次调用read会阻塞,直到管道中有数据可以读了才读取数据并返回
  3. 如果所有指向管道读端的文件描述符都关闭了(管道的读端引用计数为0),这个时候有进程向管道中写数据,那么该进程会收到一个信号SIGPIPE,通常会导致进程异常终止。
  4. 如果有指向管道读端的文件描述符没有关闭(管道的读端引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这是有进程向管道中写数据,那么在管道被写满的时候再次write会阻塞,直到管道中有空位置才能再次写入数据并返回

总结:

  • 读管道:

    • 管道中有数据,read返回实际读到的字节数
    • 管道中无数据:
      • 写端被全部关闭,read返回0(相当于读到文件的末尾)
      • 写端没有完全关闭,read阻塞等待
  • 写管道:

    • 管道读端全部被关闭,进程异常终止(进程收到SIGPIPE信号)
    • 管道读端没有全部关闭:
      • 管道已满,write阻塞
      • 管道没有满,write将数据写入,并返回实际写入的字节数

设置管道非阻塞
int flags = fcntl(fd[0],F_GETFL);//获取原来的flag
flags |= O_NONBLOCK; //修改flag的值
fcntl(fd[0],F_SETFL,flags); //设置新的flag

int main(){

    //在fork之前创建管道
    int pipefd[2];
    int ret = pipe(pipefd);
    if(ret == -1){
        perror("pipe");
        exit(0);
    }

    //创建子进程
    pid_t pid = fork();
    if(pid > 0){
        //父进程
        printf("i am parent process,pid :%d\n",getpid());

        //关闭写端
        close(pipefd[1]);

        //从管道读取端读取数据
        char buf[1024] = {0};
        int flags = fcntl(pipefd[0],F_GETFL);//获取原来的flag
        flags |= O_NONBLOCK;        //修改flag的值
        fcntl(pipefd[0],F_SETFL,flags); //设置新的flag
        while(1){
            int len = read(pipefd[0],buf,sizeof(buf));
            printf("len :%d\n",len);
            printf("parent recv : %s,pid : %d\n",buf,getpid());
            memset(buf,0,1024);
            sleep(1);

            //向管道中写入数据
            // char *str = "hello,i am parent";
            // write(pipefd[1],str,strlen(str));
            // sleep(1);
        }

    }else if(pid == 0){
        //子进程
        printf("i am child process,pid :%d\n",getpid());
        //关闭读端
        close(pipefd[0]);

        char buf[1024] = {0};
        while(1){
            char *str = "hello,i am child";
            write(pipefd[1],str,strlen(str));
            sleep(10);

            // int len = read(pipefd[0],buf,sizeof(buf));
            // printf("child recv : %s,pid : %d\n",buf,getpid());
        }
    }

有名管道

  • 匿名管道,由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道(FIFO),也叫命名管道、FIFO文件

  • 有名管道(FIFO)不同于匿名管道之处在于它提供了一个路径名与之关联,以FIFO的文件形式存在于文件系统中,并且其打开方式与打开一个普通文件是一样的,这样即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信,因此,通过FIFO不相关的进程也能交换数据

  • 一旦打开了FIFO,就能在它上面使用与操作匿名管道和其他文件的系统调用一样的I/O系统调用了(如read()、write()和close())。与管道一样,FIFO也有一个写入端和读取端,并且从管道中读取数据的顺序与写入的顺序是一样的。FIFO的名称也由此而来:先入先出

  • 有名管道(FIFO)和匿名管道(pipe)有一些特点是相同的,不同的地方在于:

    1. FIFO在文件系统中作为一个特殊文件存在,但FIFO中的内容却存放在内存中
    2. 当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便后面使用
    3. FIFO有名字,不相关的进程可以通过打开有名管道进行通信

有名管道的使用

  • 通过命令创建有名管道
    mkfifo 名字
  • 通过函数创建有名管道
    #include <sys/types.h>
    #include <sys/stat.h>
    int mkfifo(const char *pathname,mode_t mode):
  • 一旦使用mkfifo创建了一个FIFO,就可以使用open打开他,常见的文件I/O函数都可用于fifo。如:close、read、write、unlink等
  • FIFO严格遵循先进先出,对管道及FIFO的读总是从开始处返回数据,对他们的写则把数据添加到末尾。他们不支持诸如lseek()等文件定位操作

创建fifo文件

  1. 通过命令:mkfifo 名字
  2. 通过函数:int mkfifo(const char *pathname,mode_t mode);

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
参数:

  • pathname:管道的名称的路径
  • mode:文件的权限 和open的mode是一样的
    是一个八进制的数

返回值:成功返回0,失败返回-1,并设置errno

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>

int main(){

    //判断文件是否存在
    int ret = access("fifo1",F_OK);

    if(ret == -1){
        printf("管道不存在,创建管道\n");
        ret = mkfifo("fifo1",0664);

        if(ret == -1){
            perror("mkfifo");
            return -1;
        }

    }


    return 0;
}

写FIFO管道

//向管道中写数据
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(){
    //1.判断文件是否存在
    int ret = access("test",F_OK);

    if(ret == -1){
        printf("管道不存在,创建管道\n");

        //2.创建管道文件
        ret = mkfifo("test",0664);

        if(ret == -1){
            perror("mkfifo");
            return -1;
        }
    }

    //3.以只写的方式打开管道
    int fd = open("test",O_WRONLY);
    if(fd == -1){
        perror("open");
        exit(0);
    }

    //4.写入数据
    for(int i = 0;i < 100;i++){
        char buf[1024];
        sprintf(buf ,"hello,%d\n",i);
        printf("write data:%s\n",buf);
        write(fd,buf,strlen(buf));
        sleep(1);
    }

    //5.关闭文件流
    close(fd);

    return 0;
}

读FIFO管道

//从管道中读数据

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main(){
    //1.打开管道文件
    int fd = open("test",O_RDONLY);
    if(fd == -1){
        perror("open");
        exit(0);
    }

    //2.读数据
    while (1)
    {
        char buf[1024] = {0};
        int ret = read(fd,buf,sizeof(buf));
        if(ret == 0){
            printf("写端断开连接了。。。\n");
            break;
        }
        printf("recv bu : %s\n",buf);
    }
    
    //3.关闭读管道
    close(fd);

    return 0;
}

总结

有名管道的注意事项:

  1. 一个为只读而打开一个管道的进程会阻塞,直到另外一个进程为写打开管道
  2. 一个为只写而打开一个管道的进程会阻塞,直到另外一个进程为读打开管道

读管道:
管道中有数据,read返回实际读到的字节数
管道中无数据:

  • 管道写端被全部关闭,read返回0(相当于读到文件末尾)
  • 管道写端被部分关闭,read阻塞等待

写管道:
管道读端被全部关闭,进程异常终止(收到一个SIGPIPE信号)
管道读端没有全部关闭:

  • 管道已经满了,write会阻塞
  • 管道没有满,write将数据写入,并返回实际写入的字节数

有名管道实现简单版聊天功能

需求:
在这里插入图片描述
进程A的代码:B的类似

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(){

    //1.判断有名管道文件是否存在
    int ret = access("fifo1",F_OK);
    if(ret == -1){
        //文件不存在
        printf("fifo1管道不存在,创建对应的有名管道");
        ret = mkfifo("fifo1",0664);
        if(ret == -1){
            perror("mkfifo");
            exit(0);
        }
    }

    ret = access("fifo2",F_OK);
    if(ret == -1){
        //文件不存在
        printf("fifo2管道不存在,创建对应的有名管道");
        ret = mkfifo("fifo2",0664);
        if(ret == -1){
            perror("mkfifo");
            exit(0);
        }
    }

    //2.以只写的方式打开管道fifo1
    int fdw = open("fifo1",O_WRONLY);
    if(fdw == -1){
        perror("open");
        exit(0);
    }
    printf("打开管道fifo1成功,等待写入..");

    //3.以只读的方式打开管道fifo2
    int fdr = open("fifo2",O_RDONLY);
    if(fdr == -1){
        perror("open");
        exit(0);
    }
    printf("打开管道fifo2成功,等待读取..");

    char buf[128];

    //4.循环写读数据
    while (1)
    {
        memset(buf,0,128);
        //获取标准输入的数据
        fgets(buf,128,stdin);
        //写数据
        ret = write(fdw,buf,strlen(buf));
        if(ret == -1){
            perror("write");
            exit(0);
        }

        //5.读管道fifo2的数据
        memset(buf,0,128);
        ret = read(fdr,buf,128);
        if(ret <= 0){//-1是读取失败,0是对面把管道关闭了
            perror("read");
            break;
        }
        printf("buf : %s\n",buf);
    }

    //6.关闭文件描述符
    close(fdw);
    close(fdr);
    

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SRv6实践项目(五):ONOS控制平面实现控制

在先前的几个小结中&#xff0c;一共了解了&#xff1a; p4的编译过程p4runtime的实现原理NDP协议的简单工作流程YANG模型的定义以及用处基于YANG的配置和状态的读写 一共实现了&#xff1a; Mininet拓扑创建p4的基本框架编写对数据平面进行订阅以实现状态读取对数据平面进行…

OJ系统刷题 第十一篇(重点题)

13463 - 折点计数&#xff08;难题&#xff01;重点题&#xff01;&#xff09; 时间限制 : 1 秒 内存限制 : 128 MB 给定 n 个整数表示一个商店连续 n 天的销售量。 如果某天之前销售量在增长&#xff0c;而后一天销售量减少&#xff0c;则称这一天为折点&#xff0c;反过来…

玩转车载影像传输技术 ,学习Opengl与Surface渲染提升车载影像传输效果

近年来&#xff0c;随着智能化汽车的快速发展&#xff0c;车载倒车影像逐渐成为了汽车安全辅助系统的标配&#xff0c;而高清传输的倒车影像则成为了目前主流的倒车影像传输方式。在这一过程中&#xff0c;Opengl与Surface渲染技术的应用也是不可或缺的一环。 一、高清传输倒车…

E. Archaeology(纯思维)

Problem - E - Codeforces 爱丽丝买了一个刚果总理视频的订阅&#xff0c;正在看一部关于苏格兰卡特林湖的因子岛的考古发现的纪录片。考古学家发现了一本书&#xff0c;其年代和来源都不明。也许爱丽丝可以对它进行一些解释&#xff1f; 这本书包含一串字符 "a"、&…

【AI绘画】Stable Diffusion的介绍及程序示例

Stable Diffusion 1.背景2.StableD 的原理3.StableD 的应用3.1.如何使用 StableD 进行图像生成3.2 图像生成与编辑3.2.1 生成新图像3.2.2 图像编辑 1.背景 近年来&#xff0c;随着人工智能技术的发展&#xff0c;图像生成和合成技术得到了很大的发展。Stable Diffusion (Stable…

MyBatis的关联映射和缓存机制

学习目标&#xff1a; 了解数据表之间的三种关联关系了解对象之间的三种关系熟悉关联关系中的嵌套查询和嵌套结果掌握一对一关联映射掌握—对多关联映射掌握多对多关联映射熟悉Mybatis的缓存机制 文章概述&#xff1a; 前面几章介绍了MyBatis的基本用法、关联映射和动态SQL等…

CompletableFuture异步编排

CompletableFuture异步编排 1、CompletableFuture异步编排1.1 为什么需要异步编排1.2 CompletableFuture介绍1.3 创建异步对象1.4 线程串行化与并行化方法1.5 多任务组合1.6 优化商品详情页(业务代码)1.6.1 未优化之前的代码1.6.2 使用CompletableFuture异步编排1.6.3 测试功能…

Linux 下 REST 客户端的新选择:Insomnia 3.0

正在为 Linux 桌面端找一个免费的 REST 客户端&#xff1f; 别睡不着觉了&#xff01;试试 Insomnia。 这个应用是跨平台的&#xff0c;可以工作在 Linux、macOS、Windows。开发者 Gregory Schier 告诉我们他创造这个应用是为了“帮助开发者处理和 REST API 的通信”。他还说&a…

如何在Java中创建临时文件?

在Java程序中&#xff0c;有时需要创建临时文件来暂存数据或者执行某些操作。Java提供了许多方式来创建临时文件。在本教程中&#xff0c;我们将介绍如何使用Java标准库来创建临时文件。 一、使用File.createTempFile()方法 Java标准库中的File类提供了createTempFile()方法来…

设计模式--单例模式

介绍 所谓类的单例模式 就是采取一定的方法保证在整个软件系统中对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法) 比如 Hibemate的SessionFactory 它充当数据存储源的代理 并负责创建Session对象 SessionFactory并不是轻量级的 一般情况下 一个…

Java中的Map(三种双列集合万字详解)

点击可查看单列集合Set万字详解&#xff1a;其中还包含哈希解读和底层分析。 文章目录 前言一、Map1.Map集合常用的API代码演示&#xff1a;1.Map集合的基本功能2.Map集合的获取功能3.Map的getOrDefault()方法 2.Map集合的三种遍历1.键找值、值找键2.键值对3.Lambda表达式 二、…

【C++11】晦涩难懂语法系列:可变参数模板

目录 可变参数模板 1.1 概念 1.2 可变参数模板定义 1.3 参数包的展开方式 1.3.1 递归展开参数包 1.3.2 逗号表达式展开参数包 1.4 STL的emplace系列函数 可变参数模板 1.1 概念 在C语言阶段&#xff0c;我们已经接触过可变参数&#xff0c;比如scand、printf等等 这里…

9.2 回归分析

学习目标&#xff1a; 回归分析是一种广泛应用于数据分析和预测的统计方法&#xff0c;可以用来探索自变量与因变量之间的关系并进行预测。我学习回归分析&#xff0c;我会采取以下步骤&#xff1a; 学习基本概念&#xff1a;回归分析中的基本概念包括自变量和因变量、回归系数…

运放专题:运放输入端交直流混合信号隔直放大

运放输入不隔直放大 运放输入端不隔直&#xff0c;那么经过运放放大后&#xff0c;交流成分放大了&#xff0c;直流成分也被放大了。看下面的仿真&#xff1a; 交流信号为&#xff1a;振幅3V, 频率5K的正弦波&#xff0c;直流偏置为1V 可以看到&#xff0c;交流信号被放大的…

【Linux】匿名管道代码实现-mypipe

文章目录 管道介绍什么是管道&#xff1a;管道的原理管道的特点 具体代码详写创建初始文件makefile编写定义任务列表-task.hpp分阶段代码编写总代码展示: ctrlProcess.cc 编写头文件包含(如有不会,自己查谷歌)定义全局变量以解耦main,函数框架EndPoint定义creatProcess 创建管道…

Apollo配置中心使用篇

Apollo配置中心使用篇 常见配置中心对比Apollo核心概念Apollo核心特性Apollo架构设计各模块介绍服务端设计客户端设计Apollo与Spring集成的底层原理 Apollo安装安装apollo-portalconfig service和admin service部署多网卡问题解决修改Portal环境配置调整ApolloPortal配置 Apoll…

【产品设计】用户操作日志

日志记录了代码的执行过程&#xff0c;根据目的不同&#xff0c;可以分为系统日志和操作日志。 一、什么是日志 日志记录了代码的执行过程。根据目的不同&#xff0c;可分为系统日志和操作日志。 1&#xff09;系统日志 记录系统中硬件、软件和系统问题的信息&#xff0c;同…

C#基础学习--枚举器和迭代器

目录 枚举器和可枚举类型 IEnumerator 接口 IEnumerable 接口 实现 IEnumerable 和 IEnumerator的示例 泛型枚举接口 迭代器 迭代器块 使用迭代器来创建枚举器 使用迭代器来创建可枚举类型 常见迭代器模式 产生多个可枚举类型 将迭代器作为属性 迭代器实质 枚举器和可…

【分享】比ChatGPT还厉害?可以自主解决复杂任务的Auto-GPT迅速走红(内含体验地址)

哈喽&#xff0c;大家好&#xff0c;我是木易巷~ 最近木易巷在了解Auto GPT&#xff0c;今天给大家分享一下~ 自主解决复杂任务的Auto-GPT 什么是Auto-GPT&#xff1f; Auto-GPT 是一款开源 Python 应用程序&#xff0c;由开发者用户 Significant Gravitas 于 2023 年 3 月 30…

钉钉接入“通义千问”大模型,输入斜杠“/”唤起智能服务

4月18日&#xff0c;钉钉总裁叶军在2023春季钉峰会上宣布&#xff0c;钉钉正式接入阿里巴巴“通义千问”大模型&#xff0c;输入“&#xff0f;”在钉钉即可唤起 10 余项 AI 能力&#xff0c;叶军现场演示了群聊、文档、视频会议及应用开发四个场景。 现场展示中&#xff0c;只…