linux系统(进程间通信)06_IPC概念,pipe管道,fifo通信,mmap 共享映射区

news2024/11/16 19:26:19

01 学习目标

1.熟练使用pipe进行父子进程间通信
2.熟练使用pipe进行兄弟进程间通信
3.熟练使用fifo进行无血缘关系的进程间通信
4.熟练掌握mmap函数的使用
5.掌握mmap创建匿名映射区的方法
6.使用mmap进行有血缘关系的进程间通信
7.使用mmap进行无血缘关系的进程间通信

02 IPC概念(InterProcess Communication)

IPC:InterProcess Communication 进程间通信,通过内核提供的缓冲区进行数据交换的机制。
在这里插入图片描述
IPC通信的方式有几种:

  • pipe 管道 --最简单
  • fifo 有名管道
  • mmap 文件映射共享IO --速度最快
  • 本地socket --最稳定
  • 信号 --携带信息量最小
  • 共享内存
  • 消息队列

03 pipe管道

1.管道的概念

pipe通信

常见的通信方式:单工(广播),半双工(对讲机),全双工(打电话)
管道:半双工通信

半双工通信:同一时刻只能读或者写。
在这里插入图片描述

2.管道通信举例

管道函数:

int pipe(int pipefd[2])

  • pipefd 读写文件描述符,0 代表读,1 代表写
  • 返回值:失败返回-1,成功返回0
#include<stdio.h>
#include<unistd.h>

int main()
{
	int fd[2];
	pipe(fd);
	pid_t pid = fork();
	
	if(pid==0)
	{
		//son
		sleep(3);
		write(fd[1],"hello",5);
	}
	else if(pid>0)
	{
		//parent
		char buf[12]={0};
		int ret=read(fd[0],buf,sizeof(buf));
		if(ret>0)
		{
			write(STDOUT_FILENO,buf,ret);
		}
	}
	return 0;
}

read默认是阻塞的,所以子函数sleep时,也会输出
在这里插入图片描述

3.父子进程实现ps-grep命令

父子进程实现pipe通信,实现ps aux|grep bash 功能
在这里插入图片描述
pipe_ps.c:

#include<stdio.h>
#include<unistd.h>

int main()
{
	int fd[2];
	pipe(fd);
	
	pid_t pid = fork();
	if(pid == 0)
	{
		//son
		//son -->ps
		//1.先重定向
		dup2(fd[1],STDOUT_FILENO);//标准输出重定向到管道写端
		//2.execlp
		execlp("ps","ps","aux",NULL);
	}
	else if(pid>0)
	{
		//parent
		//1.先重定向,标准输入重定向到管道读端
		dup2(fd[0],STDIN_FILENO);
		//2.execlp
		execlp("grep","grep","bash",NULL);
	}
	return 0;
}

产生僵尸进程,grep进程也存在,没有退出
在这里插入图片描述
# 加图

代码的问题:
父进程认为还有写端存在,就有可能还有人给发数据,继续等待。
改造:两进程一个负责写,一个负责读。

#include<stdio.h>
#include<unistd.h>

int main()
{
	int fd[2];
	pipe(fd);
	
	pid_t pid = fork();
	if(pid == 0)
	{
		//son
		//son -->ps
		//关闭读端
		close(fd[0]);
		//1.先重定向
		dup2(fd[1],STDOUT_FILENO);//标准输出重定向到管道写端
		//2.execlp
		execlp("ps","ps","aux",NULL);
	}
	else if(pid>0)
	{
		//parent
		//关闭写端
		close(fd[1]);
		//1.先重定向,标准输入重定向到管道读端
		dup2(fd[0],STDIN_FILENO);
		//2.execlp
		execlp("grep","grep","bash",NULL);
	}
	return 0;
}

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

4.管道的读写行为

读管道:

  • 写端全部关闭 --read读到0,相当于读到文件末尾
  • 写端没有全部关闭
    有数据 --read读到数据
    没有数据 --read阻塞,fcntl函数可以更改非阻塞

写管道:

  • 读端全部关闭 --?产生一个信号SIGPIPE,程序异常终止
  • 读端未全部关闭
    管道已满 --write阻塞 --如果要显示现象,读端一直不读,写端狂写
    管道未满 --write正常写入
    pipe.c:
#include<stdio.h>
#include<unistd.h>

int main()
{
	int fd[2];
	pipe(fd);
	pid_t pid = fork();
	
	if(pid==0)
	{
		//son
		sleep(3);
		close(fd[0]);//关闭读端
		write(fd[1],"hello",5);
		close(fd[1]);
		while(1)
		{
			sleep(1);
		}
	}
	else if(pid>0)
	{
		//parent
		close(fd[1]);//关闭写端
		char buf[12]={0};
		while(1)
		{
			int ret=read(fd[0],buf,sizeof(buf));
			if(ret == 0)
			{
				printf("read over!\n");
				break;
			}
			if(ret>0)
			{
				write(STDOUT_FILENO,buf,ret);
			}
		}
	}
	return 0;
}

写端全部关闭 --read读到0,相当于读到文件末尾
在这里插入图片描述

读端全部关闭 --?产生一个信号SIGPIPE,程序异常终止

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>

int main()
{
	int fd[2];
	pipe(fd);
	pid_t pid = fork();
	
	if(pid==0)
	{
		//son
		sleep(3);
		close(fd[0]);//关闭读端
		write(fd[1],"hello",5);
		close(fd[1]);
		while(1)
		{
			sleep(1);
		}
	}
	else if(pid>0)
	{
		//parent
		close(fd[1]);//关闭写端
		close(fd[0]);
		int status;
		wait(&status);
		if(WIFSIGNALED(status))
		{
			printf("killed by %d\n",WTERMSIG(status));
		}
		//父进程只是关闭读写两端,但不退出
		while(1)
		{
			sleep(1);
		}
		char buf[12]={0};
		while(1)
		{
			int ret=read(fd[0],buf,sizeof(buf));
			if(ret == 0)
			{
				printf("read over!\n");
				break;
			}
			if(ret>0)
			{
				write(STDOUT_FILENO,buf,ret);
			}
		}
	}
	return 0;
}

在这里插入图片描述

5.管道大小和优劣

计算管道大小 512*8

long fpathconf(int fd,int name)

ulimit -a
# 加图
优点:

  • 简单

缺点:

  • 只能有血缘关系的进程通信
  • 父子进程单方向通信,如果需要双向通信,需要创建多根管道。

6.实现兄弟进程间通信,ps aux|grep bash

在这里插入图片描述
父进程中需要关闭管道的读写两端。子进程1中需要关闭管道的读端,子进程2需要关闭管道的写端。

#include<stdio.h>
#include<unistd.h>

int mian(int argc,const char* argv[])
{
	int fd[2];
	int ret=pipe(fd);
	if(ret==-1)
	{
		perror("pipe error");
		exit(1);
	}
	int i=0;
	for(i=0;i<2;++i)
	{
		pid_t pid = fork();
		if(pid==0)
		{
			break;
		}
	}
	
	//子进程1
	//ps aux
	if(i==0)
	{
		//写管道的操作,关闭读端
		close(fd[0]);
		//文件描述符重定向
		//stdout_fileno->管道的写端
		dup2(fd[1],STDOUT_FILENO);
		execlp("ps","ps","aux",NULL);
		perror("exexlp");
		exit(1);
	}
	//子进程2
	//grep "bash"
	else if(i==1)
	{
		close(fd[1]);
		dup2(fd[0],STDIN_FILENO);
		execlp("grep","grep","bash","--color=auto",NULL);
	}
	//父进程
	else if(i==2)
	{
		close(fd[0]);
		close(fd[1]);
		//回收子进程
		pid_t wpid;
		while((wpid==waitpid(-1,NULL,WNOHANG))!=-1)
		{
			if(wpid==0)
			{
				continue;
			}
			printf("child died pid = %d\n",wpid);
		}
	}
	printf("pipe[0]=%d\n",fd[0]);
	printf("pipe[1]=%d\n",fd[1]);
	
	return 0;
}

04 FIFO通信

FIFO有名管道,实现无血缘关系进程通信

  • 创建一个管道的伪文件
    (1)mkfifo myfifo 命令创建
    (2)也可以用函数int mkfifo(const char* pathname,mode_t mode)

  • 内核会针对fifo文件开辟一个缓冲区,操作fifo文件,可以操作缓冲区,实现进程间通信 --实际上就是文件读写

FIFOs:
open注意事项,打开fifo文件的时候,read端会阻塞等待write端open,write端同理,也会阻塞等待另外一端打开

fifo_w.c:

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

int main(int argc,char* argv[])
{
	if(argc!=2)
	{
		printf("./a.out fifoname\n");
		return -1;
	}
	//当前目录有一个myfifo文件
	//打开fifo文件
	printf("begin open...\n");
	int fd = open(argv[1],O_WRONLY);
	printf("end open...\n");
	//写
	char buf[256];
	int num=1;
	while(1)
	{
		memset(buf,0x00,sizeof(buf));
		sprintf(buf,"xiaoming%04d",num++);
		write(fd,buf,strlen(buf));
		sleep(1);
		//循环写
	}
	//关闭描述符
	clsoe(fd);

	return 0;	
}

fifo_r.c:

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

int main(int argc,char* argv[])
{
	if(argc!=2)
	{
		printf("./a.out fifoname\n");
		return -1;
	}
	printf("begin open read...\n");
	int fd = open(argv[1],O_RDONLY);
	printf("end open read...\n");
	
	char buf[256];
	int ret;
	while(1)
	{
		//循环读
		memset(buf,0x00,sizeof(buf));
		ret=read(fd,buf,sizeof(buf));
		if(ret>0)
		{
			printf("read:%s\n",buf);
		}
	}
	
	clos(fd);
	return 0;	
}

在这里插入图片描述
开多个read的效果,此现象表明read被取出后,就不在管道文件中。
在这里插入图片描述

05 mmap 共享映射区

1.mmap映射开始

# 加图
创建映射区

void *mmap(void *addr,size_t length,int prot,int flags,int fd,off_t offset)

  • addr 传入NUL

  • length 映射区的长度

  • prot
    PROT_READ 可读
    PROT_WRITE 可写

  • flags
    MAP_SHARED 共享的,对内存的修改会影响到源文件
    MAP_PRIVATE 私有的

  • fd 文件描述符,open打开一个文件

  • offset 偏移量

  • 返回值
    成功,返回可用的内存首地址
    失败,返回MAP_FAILED

释放映射区

int munmap(void * addr,size_t length);

  • addr 传mmap的返回值
  • length mmap创建的长度
  • 返回值

mmap.c:

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

int main()
{
	int fd=open("mem.txt",O_RDWR);

	char *mem=mmap(NULL,8,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

	if(mem == MAP_FAILED)
	{
		perror("mmap err");
		return -1;
	}
	strcpy(mem,"hello");
	
	//释放mmap
	munmap(mem,8);
	close(fd);
	return 0;
}


mem.txt:
在这里插入图片描述
运行结果:
在这里插入图片描述
将MAP_SHARED改为MAP_PRIVATE不会更改mem.txt内容。

2.mmap九问

1.如果更改mem变量的地址,释放的时候munmap,传入mem还能成功吗?
答:不能!!

2.如果对mem越界操作会怎么样?
答:文件的大小对映射区操作有影响,尽量避免

3.如果文件偏移量随便填个数会怎么样?
答:offset必须是4k的整数倍

4.如果文件描述符先关闭,对mmap映射有没有影响?
答:没有影响

5.open的时候,可以新创建一个文件来创建映射区吗?
答:不可以用大小为0的文件

6.open文件选择O_WRONLY,可以吗?
答:不可以:Permission denied

7.当选择MAP_SHARED的时候,open文件选择O_RDONLY,prot可以选择PROT_READ|PRO_WRITE吗?
答:Permission denied,SHARED的时候,映射区的权限<=open文件的权限

8.mmap什么情况下会报错?
答:很多情况

9.如果不判断返回值会怎么样?
答:会报错

3.mmap实现父子进程通信

mmap_child.c:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/mman.h>
#inclde<sys/wait.h>

int main()
{
	//先创建映射区
	int fd=open("mem.txt",O_RDWR);
	int *mem=mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
	if(mem==MAP_FAILED)
	{
		perror("mmap err");
		return -1;
	}
	
	//fork子进程
	pid_t pid =fork();
	//父进程和子线程交替修改数据
	if(pid==0)
	{
		//son
		*mem=100;
		printf("child,*mem=%d\n",*mem);
		sleep(3);
		printf("child,*mem=%d\n",*mem);
	}
	else if(pid>0)
	{
		//parent
		sleep(1);
		printf("parent,*mem=%d\n",*mem);
		*mem=1001;
		printf("parent,*mem=%d\n",*mem);
		wait(NULL);
	}
	munmap(mem,4);
	close(fd);
	return 0;
}

在这里插入图片描述

4.匿名映射

由于mmap中open的文档无作用,所以产生了匿名映射。

MAP_ANON,ANONYMOUS这两个宏在有些unix系统中没有
/dev/zero 聚宝盆,可以随意映射
/dev/null 无底洞,一般错误信息重定向到这个文件中

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/mman.h>
#inclde<sys/wait.h>

int main()
{
	*mem=mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);
	if(mem==MAP_FAILED)
	{
		perror("mmap err");
		return -1;
	}
	
	//fork子进程
	pid_t pid =fork();
	//父进程和子线程交替修改数据
	if(pid==0)
	{
		//son
		*mem=101;
		printf("child,*mem=%d\n",*mem);
		sleep(3);
		printf("child,*mem=%d\n",*mem);
	}
	else if(pid>0)
	{
		//parent
		sleep(1);
		printf("parent,*mem=%d\n",*mem);
		*mem=10001;
		printf("parent,*mem=%d\n",*mem);
		wait(NULL);
	}
	munmap(mem,4);
	close(fd);
	return 0;
}

在这里插入图片描述

5.用mmap支持无血缘关系进程通信

mmap_w.c:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/mman.h>
#inclde<sys/wait.h>

typedef struct _Student{
	int sid;
	char sname[20];
}Student;

int main(int argc,char *argv[])
{
	if(argc!=2)
	{
		printf("./a.out fifoname\n");
		return -1;
	}
	//1.open file
	int fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0666);
	int length=sizeof(Student);
	
	ftruncate(fd,length);
	
	//2.mmap Student *stu=mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

	if(stu==MAP_FAILED)
	{
		perror("mmap err");
		return -1;
	}
	int num =1;
	//3.修改内存数据
	while(1)
	{
		stu->sid=num;
		sprintf(stu->sname,"xiaoming-%03d",num++);
		sleep(1);//相当于每隔1s修改一次映射区的内容
	}
	//4.释放映射区和关闭文件描述符
	munmap(stu,length);
	close(fd);

	return 0;
}

mmap_r.c:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/mman.h>
#inclde<sys/wait.h>

typedef struct _Student{
	int sid;
	char sname[20];
}Student;

int main(int argc,char *argv[])
{
	if(argc!=2)
	{
		printf("./a.out fifoname\n");
		return -1;
	}
	//1.open file
	int fd = open(argv[1],O_RDWR);
	int length=sizeof(Student);
	//2.mmap Student *stu=mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

	if(stu==MAP_FAILED)
	{
		perror("mmap err");
		return -1;
	}
	//3.read data
	while(1)
	{
		sprintf("sid=%d,sname=%s\n",stu->sid,stu->sname);
		sleep(1);
	}
	//4.释放映射区和关闭文件描述符
	munmap(stu,length);
	close(fd);

	return 0;
}

由于mmap是内存,数据一直存在
在这里插入图片描述
如果进程要通信,flags必须设为MAP_SHARED。
在这里插入图片描述

06 实现多进程拷贝

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

int main(int argc,char *argv[])
{
	int n=5;
	//输入参数至少是3,第4个参数可以是进程个数
	if(argc<3)
	{
		printf("./a.out src dst [n] \n");
		return 0;
	}
	if(argc==4)
	{
		n=atoi(argv[3]);
	}
	//打开源文件
	int srcfd=open(argv[1],O_RDONLY);
	if(srcfd<0)
	{
		perror("open err");
		exit(1);
	}
	//打开目标文件
	int dstfd=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0664);
	if(dstfd<0)
	{
		perror("open dst err");
		exit(1);
	}
	//目标拓展,从原文件获得文件大小,stat
	struct stat sb;
	stat(argv[1],&sb);//为了计算大小
	int len=sb.st_size;
	truncate(argv[2],len);
	//将源文件映射到缓冲区
	char *psrc=mmap(NULL,len,PROT_READ,MAP_SHARED,srcfd,0);
	if(psrc==MAP_FAILED)
	{
		perror("mmap src err");
		exit(1);
	}
	//将目标文件映射
	char *pdst=mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,dstfd,0);
	if(pdst==MAP_FAILED)
	{
		perror("mmap dst err");
		exit(1);
	}
	//创建多个子进程
	int i=0;
	for(i=0;i<n;i++)
	{
		if(fork()==0)
			break;
	}
	//计算子进程需要拷贝的起点和大小
	int cpsize=len/n;
	int mod =len%n;
	//数据拷贝,memcpy
	if(i<n){//子进程
		if(i==n-1){//最后一个字进程
			memcpy(pdst+i*cpsize,psrc+i*cpsize,cpsize+mod);
		}
		else
		{
			memcpy(pdst+i*cpsize,psrc+i*cpsize,cpsize);
		}
	}
	else
	{
		for(i=0;i<n;i++)
		{
			wait(NULL);
		}
	}
	//释放映射区
	if(munmap(psrc,len)<0)
	{
		perror("munmap src err");
		exit(1);
	}
	if(munmap(pdst,len)<0)
	{
		perror("munmap dst err");
		exit(1);
	}
	//关闭文件
	close(srcfd);
	close(dstfd);
	return 0;
}

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

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

相关文章

Netfilter和iptables命令详解,从入门到精通

本文目录 1、netfilter架构和工作原则简介2、iptables操作命令说明2.1 、Filtering Specifications2.2、Target Specifications2.3、一个基于Linux的基本的防火墙的配置例子 netfilter 是Linux内核里网络部分的一个重要框架&#xff0c;内核通过netfilter完成IP报文的一些操作。…

缓存雪崩问题

缓存雪崩&#xff1a;指在同一时段大量的缓存key同时失效或者Redis服务宕机&#xff0c;导致大量的请求到达数据库&#xff0c;带来巨大的压力 解决方案&#xff1a; 1.给不同的key的TTL添加随机值 2.利用redis集群提高服务的可用性 3.给缓存业务添加降级限流策略 4.给业务添…

扫雷,咱就是一扫一大片(C语言完美递归版)

&#x1f929;本文作者&#xff1a;大家好&#xff0c;我是paperjie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 &#x1f970;内容专栏&#xff1a;这里是《C语言》专栏&#xff0c;笔者用重金(时间和精力)打造&#xff0c;基础知识一网打尽&#xff0c;希望可以…

零基础入门 Stable Diffusion - 无需显卡把 AI 绘画引擎搬进家用电脑

我从小特别羡慕会画画的伙伴。他们能够将心中的想法画出来&#xff0c;而我最高水平的肖像画是丁老头。但在接触 Stable Diffusion 之后&#xff0c;我感觉自己脱胎换骨&#xff0c;给自己贴上了「会画画」的新标签。 丁老头进化旅程 Stable Diffusion 是一个「文本到图像」的…

区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归时间序列区间预测

区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归时间序列区间预测 目录 区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 进阶版 基础版 基本介绍 MATLAB实现QRLSTM长短期记忆神经…

微波方向有哪些SCI期刊推荐? - 易智编译EaseEditing

微波方向的SCI期刊推荐包括&#xff1a; IEEE Transactions on Microwave Theory and Technology&#xff1a; 该期刊是电磁场与微波技术领域的著名期刊&#xff0c;被世界上许多研究机构和大学广泛引用。 IEEE Transactions on Antennas and Propagation&#xff1a; 该期刊…

C++学习记录——이십일 AVL树

文章目录 1、了解AVL树2、模拟实现3、旋转1、左单旋2、右单旋3、双旋&#xff08;先左后右&#xff09;4、双旋&#xff08;先右后左&#xff09; 4、检查平衡5、测试性能&#xff08;随机数&#xff09;6、删除 1、了解AVL树 如果数据有序或接近有序&#xff0c;二叉搜索树将…

Java+Python+Paddle提取长文本文章中词频,用于Echart词云图数据

公司有个需求&#xff0c;就是需要提供给echart词云图的数据&#xff0c;放在以前我们的数据来源都是从产品那直接要&#xff0c;产品也是跑的别的接口&#xff0c;那怎么行呢&#xff0c;当然有自己的一套可以随便搞了&#xff0c;那么操作来了 Java package cn.iocoder.yud…

推荐几款2023年还在用的IDE工具

近期有不少刚学编程的小伙伴来问我&#xff0c;市面上那么多IDE工具&#xff0c;该怎么选&#xff1f;今天在这里跟大家分享几款个人比较钟爱的IDE工具&#xff0c;供大家参考。 Visual Studio 优点&#xff1a;支持多种语言&#xff0c;包括C#, C, Visual Basic等&#xff0c…

【Linux】进程信号“疑问?坤叫算信号吗?“

鸡叫当然也算信号啦~ 文章目录 前言一、认识信号量二、信号的产生 1.调用系统函数向进程发信号2.由软件条件产生信号3.硬件异常产生信号总结 前言 信号在我们生活中很常见&#xff0c;下面我们举一举生活中信号的例子&#xff1a; 你在网上买了很多件商品&#xff0c;再等待不…

【跟着陈七一起学C语言】今天总结:函数、数组、指针之间的关系

友情链接&#xff1a;专栏地址 知识总结顺序参考C Primer Plus&#xff08;第六版&#xff09;和谭浩强老师的C程序设计&#xff08;第五版&#xff09;等&#xff0c;内容以书中为标准&#xff0c;同时参考其它各类书籍以及优质文章&#xff0c;以至减少知识点上的错误&#x…

深度学习实战29-AIGC项目:利用GPT-2(CPU环境)进行文本续写与生成歌词任务

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下深度学习实战29-AIGC项目&#xff1a;利用GPT-2(CPU环境)进行文本续写与生成歌词任务。在大家没有GPU算力的情况&#xff0c;大模型可能玩不动&#xff0c;推理速度慢&#xff0c;那么我们怎么才能跑去生成式的模型…

14 KVM虚拟机配置-配置虚拟设备(其它常用设备)

文章目录 14 KVM虚拟机配置-配置虚拟设备&#xff08;其它常用设备&#xff09;14.1 概述14.2 元素介绍14.3 配置示例 14 KVM虚拟机配置-配置虚拟设备&#xff08;其它常用设备&#xff09; 14.1 概述 除存储设备、网络设备外&#xff0c;XML配置文件中还需要指定一些其他外部…

Python+selenium,轻松搭建 Web 自动化测试框架

在程序员的世界中&#xff0c;一切重复性的工作&#xff0c;都应该通过程序自动执行。「自动化测试」就是一个最好的例子。 随着互联网应用开发周期越来越短&#xff0c;迭代速度越来越快&#xff0c;只会点点点&#xff0c;不懂开发的手工测试&#xff0c;已经无法满足如今的…

云渲染靠谱吗,使用云渲染会不会被盗作品?

云渲染靠谱吗、安全吗&#xff1f;如果使用 云渲染会不会被盗作品......Renderbus瑞云渲染作为一个正经的云渲染平台&#xff0c;也时不时会收到这类疑问&#xff0c;首先&#xff0c;瑞云渲染是肯定靠谱的,各位可以放心使用。另外小编也将在本篇教你如何辨别云渲染平台是否安全…

通达信W底形态选股公式,也称双底形态

W底形态&#xff0c;也称双底形态&#xff0c;是一种经典的技术分析形态&#xff0c;代表了跌势的逆转。看起来像字母 "W"&#xff0c;描述了一波下跌&#xff0c;反弹&#xff0c;再次下跌到与上一波下跌相同或相近的位置&#xff0c;最后是另一波反弹。W底形态两次…

【细读Spring Boot源码】@ComponentScan是如何生效的?

前言 在使用SpringBoot使用过程中 RestController、Service、Repository这几个注解类上都标有Component注解 启动类上标有的SpringBootApplication注解类上有个ComponentScan注解。那么ComponentScan如何把相关的对象注册到BeanFactory的&#xff1f; 找到处理ComponentScan注…

【Qt 从入门到入土】下篇

【Qt 从入门到入土】上篇 一个非常好的学习 Qt 的视频 本文目录 6. 对话框QDialog6.1 基本概念6.2 标准对话框6.3 自定义消息框6.4 消息对话框6.5 标准文件对话框 7. 布局管理器7.1 系统提供的布局控件7.2 利用widget做布局 8. 常用控件8.1 QLabel 控件使用8.2 QLineEdit8.3 其…

1_5 pytorch操作

一、torch 算子 1、torch.nn.functional.affine_grid(theta, size) 给定一组仿射矩阵(theta)&#xff0c;生成一个2d的采样位置(流场)&#xff0c;通常与 grid_sample() 结合使用,用于空间仿射变换网络&#xff0c;用于对2D或3D数据进行仿射变换。 输入&#xff1a;theta(Te…

5.20 牛奶咖啡·仙羽「重生」巡回演唱会 武汉站 告白夜浪漫收官

牛奶咖啡主唱仙羽「重生」主题巡回演唱会将于2023年5月20日浪漫收官。经历多次延期&#xff0c;「重生」巡回演唱会武汉站 终于与大家见面&#xff0c;届时会为大家带来多首传唱度极高的歌曲&#xff0c;与歌迷朋友共度一个难忘的告白夜。 关于仙羽仙羽&#xff08;kiki&#…