【Linux】进程等待
文章目录
- 进程等待
- 进程等待必要性
- 实验(见见猪跑)
- 进程等待的方法
- wait方法
- waitpid**方法**
- 宏的使用方法
- 获取子进程status
- 阻塞VS非阻塞
- 概念对比
- 非阻塞有什么好处
- 具体代码实现
- 进程的阻塞等待方式:
- 进程的非阻塞等待方式:
- 让父进程做其他任务
进程等待
进程等待必要性
- 之前讲过,子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。
- 另外,进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。
- 最后,父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对,或者是否正常退出。
- 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息
因此,进程等待是为了:
- 避免内存泄漏
- 获取子进程执行的结果
- 代码跑完,结果对->退出码
- 代码跑完,结果不对->退出码
- 代码运行异常->信号
等待就是通过系统调用,获取子进程退出码或者退出信号的方式,顺便释放内存
实验(见见猪跑)
#include<sys/types.h>
#include<sys/wait.h>
int main()
{pid_t id = fork();if(id == 0){int cnt = 10;while(cnt){printf("我是子进程:%d,父进程:%d,cnt:%d\n",getpid(),getppid(),cnt--);}exit(10);//此时都是S状态}//此时子进程变成Z状态sleep(15);pid_t ret = wait(NULL);//回收子进程if(id > 0){printf("wait success:%d\n",ret);}sleep(5);//父进程退出
}
waitpid用法;
#include<sys/types.h>
#include<sys/wait.h>
int main()
{pid_t id = fork();if(id == 0)//子进程返回0,父进程返回子进程id{int cnt = 10;while(cnt){printf("我是子进程:%d,父进程:%d,cnt:%d\n",getpid(),getppid(),cnt--);}exit(10);//退出的三种结果://1.代码跑完,结果是对的//2.代码跑完,结果是错的//3.代码没有跑完,出异常了//此时都是S状态}//此时子进程变成Z状态sleep(15);int status = 0;pid_t ret = waitpid(id,&status,0);//回收子进程//错误观念:此时status的值变成了10//因为status不是被整体使用的,有自己的位图结构if(id > 0){printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,(status & 0x7F),(status>>8)&0xFF);}//sig number:0 child exit code:10sleep(5);//父进程退出
}
监控脚本:
ps ajx | head -1 && ps axj | grep mytest | grep -v grep
第一句话是把标题拿出来
第二句话是把matest的进程信息拿出来
第三句话是把grep本身的进程信息去掉
之后写一个循环语句
while :; do ps ajx | head -1 && ps axj | grep mytest | grep -v grep; sleep 1; done
![![[Pasted image 20221212134644.png]]](https://img-blog.csdnimg.cn/da6c370e4b7a4dceb0958f6106f7d4bd.png)
(ctrl + z 退出)
进程等待的方法
wait方法
:!man 2 wait //可以查看到相关wait的用法信息
需要包含两个头文件:
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int* status);
返回值:
成功返回被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
waitpid方法
pid_ t waitpid(pid_t pid, int *status, int options);
返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数: pid: Pid=-1,等待任一个子进程。与wait等效。 Pid>0.等待其进程ID与pid相等的子进程。 status: WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出) WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码) options: WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。
这里有一个问题:
status按理来说是会返回信号+退出码的,但是一个整数怎么能返回两个整数呢?
所以我们不应该吧status当作一个完整的整数,而是应该看作位图结构(后面会详解)
宏的使用方法
int ret = waitpid(id,&status,0)
if(ret > 0)
{//是否正常退出if(WIFEXITED(status)){//判断子进程运行结果是否OKprintf("exit code :%d\n",WEXITSTATUS(status));}else//出异常了(比如kill -9){//TODOprintf("child exit not normal\n");}
}
- 如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息。
- 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞。
- 如果不存在该子进程,则立即出错返回。
![![[Pasted image 20221112090227.png]]](https://img-blog.csdnimg.cn/b7917dc3df42435791ff98b827ebc41c.png)
获取子进程status
wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
如果传递NULL,表示不关心子进程的退出状态信息。
否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(本身是32位,但是这里我们只研究status低16比特位):
1.代码跑完,结果是对的
2.代码跑完,结果是错的
3.代码没有跑完,出异常了
终止信号(即退出码)用来表示是否正常结束(为0则表示正常退出)
用退出状态表示结果是否正确(通过kill -l进行对应数字的查看(比如发生段错误,除0操作等)),此时退出码是否为0或者是其他的,都无意义,我们不讨论它.
第七位是信号编号
![![[Pasted image 20221112090250.png]]](https://img-blog.csdnimg.cn/0e535e0256254546aa472f2a6ffa6fc2.png)
获取退出状态:
(status>>8)&0xFF )
获取终止信号:
``(status & 0x7F))
#include<sys/types.h>
#include<stdio.h>
#include<sys/wait.h>
int main()
{pid_t id = fork();if (id == 0){int cnt = 10;while (cnt){printf("我是子进程:%d,父进程:%d,cnt:%d\n", getpid(), getppid(), cnt--);sleep(1);}}int status = 0;//1.让OS释放子进程的僵尸状态//2.获取子进程的退出结果//3.在等待期间,子进程没有退出的时候,父进程只能阻塞等待.pid_t ret = waitpid(id, &status, 0);if (id > 0){printf("wait success: %d,sig number : %d ,child exit code: %d\n",ret,(status & 0x7F),(status>>8)&0xFF );}}
测试代码:
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main( void )
{ pid_t pid; if ( (pid=fork()) == -1 ) perror("fork"),exit(1); if ( pid == 0 ){ sleep(20); exit(10); } else { int st; int ret = wait(&st); if ( ret > 0 && ( st & 0X7F ) == 0 ){ // 正常退出 printf("child exit code:%d\n", (st>>8)&0XFF); } else if( ret > 0 ) { // 异常退出 printf("sig code : %d\n", st&0X7F ); } }
}
测试结果: [root@localhost linux]# ./a.out #等20秒退出 child exit code:10 [root@localhost linux]# ./a.out #在其他终端kill掉 sig code : 9
等待的本质:
监测子进程退出的信息
并且将子进程退出信息通过status拿回来
这个信息(exit code ,signal)在子进程的PCB中
![![[进程控制 2022-12-12 14.39.31.excalidraw]]](https://img-blog.csdnimg.cn/3c1092afbaf544c5a342d563086a8e68.png)
再谈进程退出:
1.进程退出会变成僵尸进程->会把自己的退出结果写到自己的task_struct
2.wait/waitpid是一个系统调用->OS->OS有资格也有能力去读取子进程的task_struct
阻塞VS非阻塞
概念对比
例子:
1.不挂电话,监测李四的状态->阻塞
2.张三->李四,本质是状态检测,如果没有就绪,直接返回->每一次都是一次非阻塞等待->多次非阻塞等待我们称为:轮询
打电话->系统调用wait/waitpid
张三->父进程
李四->子进程
我们上面写的代码都是阻塞等待
轮询等待:
#include<sys/types.h>
#include<stdio.h>
#include<sys/wait.h>
int main()
{pid_t id = fork();if (id == 0){int cnt = 10;while (cnt){printf("我是子进程:%d,父进程:%d,cnt:%d\n", getpid(), getppid(), cnt--);sleep(1);}}int status = 0;while(1)//这是一个死循环,作为轮询等待的一个条件!{pid_t ret = waitpid(id, &status, WNOHANG);//wnohang:非阻塞:子进程没有退出时,父进程监测之后立即返回//如果没有设置WNOHANG,则会卡在这一步,除非子进程退出,或者你的id值设置得有问题.否则不会执行下面的代码if(ret == 0)//设置了WNOHANG才会可能出现返回值为0的情况{//waitpid调用成功&&子进程没有退出,我的waitpid没有等待失败//仅仅是监测到了子进程没有退出printf("wait done,but child is running\n",);}else if(ret > 0){//1.waitpid调用成功(等待成功)&&子进程退出了 printf("wait success: %d,sig number : %d ,child exit code: %d\n",ret,(status & 0x7F),(status>>8)&0xFF );break;}else{//waitpid调用失败,返回值为-1//eg.传入的id参数传错了printf("waitpid call failed\n");break;}sleep(1);}
}
非阻塞有什么好处
不会占用父进程的所有精力,可以在轮询期间干干其他的
[[指针进阶]]
[[typedef函数进阶]]
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
#include <stdlib.h>#define TASK_NUM 10typedef void (*func_t)();
func_t other_task[TASK_NUM] = {NULL};void sync_disk()
{printf("这是一个刷新磁盘的任务\n");
}
void sync_log()
{printf("这是一个同步日志的任务\n");
}
void net_send()
{printf("这是一个网络发送的任务\n");
}void LoadTask(func_t func)
{for (int i = 0; i < TASK_NUM; i++){if (other_task[i] == NULL){other_task[i] = func;break;}}
}void InitTask()
{for (int i = 0; i < TASK_NUM; i++)other_task[i] = NULL;LoadTask(sync_disk);LoadTask(sync_log);LoadTask(net_send);
}void RunTask()
{for (int i = 0; i < TASK_NUM; i++){if (other_task[i] == NULL)continue;other_task[i]();}
}int main()
{pid_t id = fork();assert(id >= 0);if (id == 0){int cnt = 5;while (cnt){printf("我是子进程,我的pid是:%d,我的ppid是%d,我还有%dS存活\n", getpid(), getppid(), cnt--);sleep(1);}printf("我已经退出\n");exit(11);}InitTask();while (1){sleep(1);int status;pid_t ret_id = waitpid(id, &status, WNOHANG);if (ret_id > 0){printf("我是父进程,我已经回收子进程,ret_id是%d,退出码为%d,退出信号为%d\n", ret_id, (status >> 8) & 0xFF, status & 0x7F);exit(0);}else if (ret_id == 0){RunTask();continue;}else{printf("调用出错\n");}}
}
具体代码实现
进程的阻塞等待方式:
#define _CRT_SECURE_NO_WARNINGS 1
int main()
{pid_t pid;pid = fork();if (pid < 0) {printf("%s fork error\n", __FUNCTION__);return 1;}else if (pid == 0) { //childprintf("child is run, pid is : %d\n", getpid());sleep(5);exit(257);}else {int status = 0;pid_t ret = waitpid(-1, &status, 0);//阻塞式等待,等待5Sprintf("this is test for wait\n");if (WIFEXITED(status) && ret == pid) {printf("wait child 5s success, child return code is :%d.\n", WEXITSTATUS(status));}else {printf("wait child failed, return.\n");return 1;}}return 0;
}
运行结果:
[root@localhost linux] # . / a.out
child is run, pid is : 45110
this is test for wait
wait child 5s success, child return code is : 1.
进程的非阻塞等待方式:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{pid_t pid;pid = fork();if (pid < 0) {printf("%s fork error\n", __FUNCTION__);return 1;}else if (pid == 0) { //childprintf("child is run, pid is : %d\n", getpid());sleep(5);exit(1);}else {int status = 0;pid_t ret = 0;do{ret = waitpid(-1, &status, WNOHANG);//非阻塞式等待->子进程没有退出,父进程检测时候,立即返回if (ret == 0) {//子进程没有退出,我的waitpid没有等待失败//仅仅是监测到了子进程没有退出printf("child is running\n");}sleep(1);} while (ret == 0);if (WIFEXITED(status) && ret == pid) {printf("wait child 5s success, child return code is :%d.\n", WEXITSTATUS(status));}else {printf("wait child failed, return.\n");return 1;}}return 0;
}
让父进程做其他任务
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>#define TASK_NUM 10// 要保存的任务相关的
typedef void (*func_t)(); //?
func_t other_task[TASK_NUM] = {NULL}; //函数指针数组// 预设一批任务
void sync_disk()
{printf("这是一个刷新数据的任务!\n");
}
void sync_log()
{printf("这是一个同步日志的任务!\n");
}
void net_send()
{printf("这是一个进行网络发送的任务!\n");
}//将任务加载进任务列表
int LoadTask(func_t func)
{int i = 0;for(; i < TASK_NUM; i++){if(other_task[i] == NULL) break;}if(i == TASK_NUM) return -1;else other_task[i] = func;return 0;
}void InitTask()
{for(int i = 0; i < TASK_NUM; i++) other_task[i] = NULL;LoadTask(sync_disk);LoadTask(sync_log);LoadTask(net_send);
}void RunTask()
{for(int i = 0; i < TASK_NUM; i++){if(other_task[i] == NULL) continue;other_task[i]();}
}int main()
{pid_t id = fork();if(id == 0){//子进程int cnt = 50;while(cnt){printf("我是子进程,我还活着呢,我还有%dS, pid: %d, ppid%d\n", cnt--, getpid(), getppid());sleep(1);//int *p = NULL;//*p = 100;}exit(111);}InitTask();// 父进程//pid_t ret_id = wait(NULL);while(1){int status = 0;pid_t ret_id = waitpid(id, &status, WNOHANG); // 夯住了if(ret_id < 0){printf("waitpid error!\n");exit(1);}else if(ret_id == 0){RunTask();sleep(1);continue;}else{if(WIFEXITED(status)) // 是否收到信号{printf("wait success, child exit code: %d\n", WEXITSTATUS(status));}else{printf("wait success, child exit signal: %d\n", status & 0x7F);}// printf("我是父进程,等待子进程成功, pid: %d, ppid: %d, ret_id: %d, child exit code: %d, child exit signal: %d\n",\// getpid(), getppid(), ret_id, (status>>8)&0xFF, status & 0x7F);break;}}
相关文章:
【Linux】进程等待
文章目录 进程等待进程等待必要性实验(见见猪跑)进程等待的方法wait方法waitpid**方法**宏的使用方法获取子进程status 阻塞VS非阻塞概念对比非阻塞有什么好处 具体代码实现进程的阻塞等待方式:进程的非阻塞等待方式:让父进程做其他任务 进程等待 进程等待必要性 之前讲过&am…...
电视「沉浮录」:跌出家电“三大件”?
【潮汐商业评论/原创】 “这年头谁还看电视,家里电视近一年都没打开过了,我明天就打算把它二手卖掉。”想到已落灰许久的电视机,Andy打开了二手平台。 “要不是这几年孩子网课多,我是真没考虑换新电视,家里用了8年的…...
前端实现调用打印机和小票打印(TSPL )功能
Ⅰ- 壹 - 使用需求 前端 的方式 点击这个按钮,直接让打印机打印我想要的东西 Ⅱ - 贰 - 小票打印 目前比较好的方式就是直接用 TSPL 标签打印指令集, 基础环境就不多说了,这个功能的实现就是利用usb发送指令,现在缺少个来让我们能够和usb沟通的工具,下面这就是推…...
串口通信(6)应用定时器中断+串口中断实现接收一串数据
本文为博主 日月同辉,与我共生,csdn原创首发。希望看完后能对你有所帮助,不足之处请指正!一起交流学习,共同进步! > 发布人:日月同辉,与我共生_单片机-CSDN博客 > 欢迎你为独创博主日月同…...
【WinForm详细教程六】WinForm中的GroupBox和Panel 、TabControl 、SplitContainer控件
文章目录 1.GroupBox和Panel2.TabControl3.SplitContainer 1.GroupBox和Panel GroupBox:是一个分组容器,提供一个框架将相关的控件组织在一起,它有标题、边框,但没有滚动条。 Panel:也是一个容器控件,用来…...
gradle与maven
Gradle 和 Maven 都是流行的构建工具,通常用于构建和管理 Java 和 Android 项目。它们都可以自动下载依赖库、编译代码、运行测试、打包和发布等。 以下是对 Gradle 和 Maven 的介绍: Gradle: Gradle 是一个基于 Groovy 和 Kotlin 的构建自…...
2.Docker基本架构简介与安装实战
1.认识Docker的基本架构 下面这张图是docker官网上的,介绍了整个Docker的基础架构,我们根据这张图来学习一下docker的涉及到的一些相关概念。 1.1 Docker的架构组成 Docker架构是由Client(客户端)、Docker Host(服务端)、Registry(远程仓库)组成。 …...
拓世法宝 | 数字经济崛起,美业如何抓住流量风口?
爱美之心,人皆有之。无论男女,都会很自然地对美好事物燃起兴致,跟高颜值相关的事物总能聚集注意力。例如直播平台里的美女网红收割流量赚得盆满钵满,面庞俊俏的年轻偶像吸引万千粉丝,还有“央视最美记者”王冰冰、“最…...
Scala 泛型编程
1. 泛型 Scala 支持类型参数化,使得我们能够编写泛型程序。 1.1 泛型类 Java 中使用 <> 符号来包含定义的类型参数,Scala 则使用 []。 class Pair[T, S](val first: T, val second: S) {override def toString: String first ":" sec…...
索引失效的场景有哪些?
虽然你这列上建了索引,查询条件也是索引列,但最终执行计划没有走它的索引。下面是引起这种问题的几个关键点。 列与列对比 某个表中,有两列(id和c_id)都建了单独索引,下面这种查询条件不会走索引 select…...
Java进阶04 final关键字、abstract抽象、interface接口、JDK8与JDK9中接口的区别、内部类和匿名类
文章目录 一、final关键字二、abstract关键字三、接口interface四、JDK8和JDK9中接口的区别五、内部类 一、final关键字 final可以修饰类、方法、变量 用final修饰类 表示此类不能被继承 用final修饰方法 表示方法不可以被重写 用final修饰变量 既可以修饰成员变量也可以修饰…...
Python的web自动化学习(五)Selenium的隐式等待(元素定位)
引言: WebDriver隐式等待是一种全局性的等待方式,它会在查找元素时设置一个固定的等待时间。当使用隐式等待时,WebDriver会在查找元素时等待一段时间,如果在等待时间内找到了元素,则立即执行下一步操作;如果…...
20231102从头开始配置cv180zb的编译环境(欢迎入坑,肯定还有很多问题等着你)
20231102从头开始配置cv180zb的编译环境(欢迎入坑,肯定还有很多问题等着你) 2023/11/2 11:31 (欢迎入坑,本篇只是针对官方的文档整理的!只装这些东西你肯定编译不过的,还有很多问题等着你呢&…...
CentOS 安装HTTP代理服务器 Squid
参考:大部分摘自此文,做了少部分修改 Squid 是一个功能全面的缓存代理服务器,它支持著名的网络协议像 HTTP,HTTPS,FTP 等等。将 Squid 放在网页服务器的前端,通过缓存重复请求,过滤网络流量等&…...
ubuntu下开发提效的小tips
一、常用操作使用简写的别名,写进bashrc文件中 背景:经常需要cd至某个文件夹中,然后再执行对应的操作;写进bashrc文件中后,可以直接用缩略命令替代这一连串的命令; 用到的工具: 设置命令别名a…...
Java反射详解:入门+使用+原理+应用场景
反射非常强大和有用,现在市面上绝大部分框架(spring、mybatis、rocketmq等等)中都有反射的影子,反射机制在框架设计中占有举足轻重的作用。 所以,在你Java进阶的道路上,你需要掌握好反射。 怎么才能学好反射,我们需要…...
PostgreSQL 工具的相关介绍
1.1 psql工具 psql是PostgreSQL中的一个命令行交互式客户端工具,类似 Oracle中的命令行工具sqlplus,它允许用户交互地键入SQL语句或命 令,然后将其发送给PostgreSQL服务器,再显示SQL语句或命令的结 果。 1.2 psql的简单使用 使用…...
结合组件库实现table组件树状数据的增删改
如图所示,可以实现树状数据的新增子项,新增平级,删除。主要用到了递归 代码: <template><el-table :data"tableData" style"width: 100%; margin-bottom: 20px" row-key"id" border def…...
Microsoft 365 管理自动化
Microsoft 365 服务被大多数组织广泛使用,每天生成的数据量巨大。解决 Microsoft 365 中的问题可能非常困难,并且使用多个管理中心来保护组织变得复杂。本机控制台还缺少某些批量管理任务、全面的审计报告和基于角色的精细访问控制。 Microsoft 360 管理…...
unraid 安装并设置 zerotier 内网穿透安装 unraid 局域网内其他设备
Read Original 最近看了以下两个文章,感谢发布的各种精彩文章,让我受益匪浅。OPENWRT 的固件在设置了,【自动允许客户端 NAT】后,可以直接访问局域网其他设备,而我 unraid 部署 zerotier 后,只能访问 unra…...
SVN 报错 Previous operation has not finished,提示需要 clean up
SVN报错"Previous operation has not finished"通常是由于操作中断导致工作副本被锁定。 解决方法按优先级推荐: 1)首选执行Cleanup操作,勾选"Cleanup working copy status"和"Break write locks";…...
5分钟免费解决NVIDIA显卡显示器色彩过饱和的终极方案
5分钟免费解决NVIDIA显卡显示器色彩过饱和的终极方案 【免费下载链接】novideo_srgb Calibrate monitors to sRGB or other color spaces on NVIDIA GPUs, based on EDID data or ICC profiles 项目地址: https://gitcode.com/gh_mirrors/no/novideo_srgb 你是否曾经发现…...
深度解析碧蓝航线自动化脚本:架构设计与智能调度创新
深度解析碧蓝航线自动化脚本:架构设计与智能调度创新 【免费下载链接】AzurLaneAutoScript Azur Lane bot (CN/EN/JP/TW) 碧蓝航线脚本 | 无缝委托科研,全自动大世界 项目地址: https://gitcode.com/gh_mirrors/az/AzurLaneAutoScript 在移动游戏…...
智能消费记账|基于SSM+vue的大学生智能消费记账系统(源码+数据库+文档)
智能消费记账系统 目录 基于SSMvue的大学生智能消费记账系统 一、前言 二、系统设计 三、系统功能设计 1 用户列表 2 预算信息管理 3 预算类型管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍&#x…...
终极指南:3步实现Switch手柄在Windows PC上的完美XInput兼容
终极指南:3步实现Switch手柄在Windows PC上的完美XInput兼容 【免费下载链接】BetterJoy Allows the Nintendo Switch Pro Controller, Joycons and SNES controller to be used with CEMU, Citra, Dolphin, Yuzu and as generic XInput 项目地址: https://gitcod…...
ERC-1155终极指南:统一数字资产管理的未来标准
ERC-1155终极指南:统一数字资产管理的未来标准 引言 在数字资产爆炸式增长的时代,管理游戏道具、数字藏品和供应链凭证等多样化的资产,常常需要部署多个独立的智能合约,导致成本高昂且操作繁琐。有没有一种方案能“一合约统管万…...
金属3D打印光束整形:两大路线正面PK
作为金属3D打印技术的最新发展,开展光束整形技术研究的企业越来越多,研发的进程也越来越深。3D打印技术参考注意到,国外由EOS引领该技术发展,同时还有Aconity3D和DMG Mori等行业领导者;在国内,铂力特、华曙…...
Python报错Resource averaged_perceptron_tagger_eng not found
用python标注英文单词词形时,报错: import nltk nltk.download(‘averaged_perceptron_tagger_eng’) Resource averaged_perceptron_tagger_eng not found. 估计是因为网络问题,遂改用离线安装的方式。 第一步:下载averaged_perc…...
实战指南:如何将SPIN的超像素思想,迁移到你的图像修复项目里(附思路)
超像素注意力机制在图像修复中的工程实践指南 当你在处理一张模糊的老照片时,是否曾为那些无法辨认的面部细节而苦恼?或者在增强低分辨率监控画面时,发现传统方法总是让边缘变得生硬不自然?这些问题背后,隐藏着一个被大…...
用P4和BMv2在Ubuntu上快速搭建一个可编程三层交换机(附完整代码和避坑指南)
用P4和BMv2在Ubuntu上构建可编程交换机的实战指南 当传统网络设备无法满足灵活的业务需求时,P4语言正在重新定义网络数据平面的可能性。想象一下,你可以在30分钟内将一台普通Ubuntu机器变成支持自定义转发逻辑的三层交换机——这正是P4带来的变革力量。本…...
