深入理解linux惊群效应(超详细)

一口Linux 2024-05-31 11:02

点击左上方蓝色“一口Linux”,选择“设为星标

第一时间看干货文章 

【干货】嵌入式驱动工程师学习路线
【干货】Linux嵌入式知识点-思维导图-免费获取
【就业】一个可以写到简历的基于Linux物联网综合项目
【就业】找工作简历模版



 1

linux惊群效应

详细的介绍什么是惊群,惊群在线程和进程中的具体表现,惊群的系统消耗和惊群的处理方法。

1、惊群效应是什么?

惊群效应也有人叫做雷鸣群体效应,不过叫什么,简言之,惊群现象就是多进程(多线程)在同时阻塞等待同一个事件的时候(休眠状态),如果等待的这个事件发生,那么他就会唤醒等待的所有进程(或者线程),但是最终却只可能有一个进程(线程)获得这个时间的“控制权”,对该事件进行处理,而其他进程(线程)获取“控制权”失败,只能重新进入休眠状态,这种现象和性能浪费就叫做惊群。

为了更好的理解何为惊群,举一个很简单的例子,当你往一群鸽子中间扔一粒谷子,所有的各自都被惊动前来抢夺这粒食物,但是最终注定只可能有一个鸽子满意的抢到食物,没有抢到的鸽子只好回去继续睡觉,等待下一粒谷子的到来。这里鸽子表示进程(线程),那粒谷子就是等待处理的事件。

2.惊群效应到底消耗了什么?

我想你应该也会有跟我一样的问题,那就是惊群效应到底消耗了什么?

(1)、系统对用户进程/线程频繁地做无效的调度,上下文切换系统性能大打折扣。

(2)、为了确保只有一个线程得到资源,用户必须对资源操作进行加锁保护,进一步加大了系统开销。

是不是还是觉得不够深入,概念化?看下面:

*1、上下文切换(context switch)过高会导致cpu像个搬运工,频繁地在寄存器和运行队列之间奔波,更多的时间花在了进程(线程)切换,而不是在真正工作的进程(线程)上面。直接的消耗包括cpu寄存器要保存和加载(例如程序计数器)、系统调度器的代码需要执行。间接的消耗在于多核cache之间的共享数据。

*2、通过锁机制解决惊群效应是一种方法,在任意时刻只让一个进程(线程)处理等待的事件。但是锁机制也会造成cpu等资源的消耗和性能损耗。目前一些常见的服务器软件有的是通过锁机制解决的,比如nginx(它的锁机制是默认开启的,可以关闭);还有些认为惊群对系统性能影响不大,没有去处理,比如lighttpd。

3.惊群效应的庐山真面目。

让我们从进程和线程两个方面来揭开惊群效应的庐山真面目:

*1)accept()惊群:

首先让我们先来考虑一个场景:

主进程创建了socket、bind、listen之后,fork()出来多个进程,每个子进程都开始循环处理(accept)这个listen_fd。每个进程都阻塞在accept上,当一个新的连接到来时候,所有的进程都会被唤醒,但是其中只有一个进程会接受成功,其余皆失败,重新休眠。

那么这个问题真的存在吗?

历史上,Linux的accpet确实存在惊群问题,但现在的内核都解决该问题了。即,当多个进程/线程都阻塞在对同一个socket的接受调用上时,当有一个新的连接到来,内核只会唤醒一个进程,其他进程保持休眠,压根就不会被唤醒。

不妨写个程序测试一下,眼见为实:

fork_thunder_herd.c:

#include
#include
#include
#include
#include
#include
#include
#include

#define PROCESS_NUM 10
int main()
{
int fd = socket(PF_INET, SOCK_STREAM, 0);
int connfd;
int pid;

char sendbuff[1024];
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(1234);
bind(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
listen(fd, 1024);
int i;
for(i = 0; i < PROCESS_NUM; ++i){
pid = fork();
if(pid == 0){
while(1){
connfd = accept(fd, (struct sockaddr *)NULL, NULL);
snprintf(sendbuff, sizeof(sendbuff), "接收到accept事件的进程PID = %d\n", getpid());

send(connfd, sendbuff, strlen(sendbuff)+1, 0);
printf("process %d accept success\n", getpid());
close(connfd);
}
}
}
//int status;
wait(0);
return 0;
}

这个程序模拟上面的场景,当我们用telnet连接该服务器程序时,会看到只返回一个进程pid,即只有一个进程被唤醒。

我们用strace -f来追踪fork子进程的执行:

编译:cc fork_thunder_herd.c -o server

一个终端执行strace -f ./server 你会看到如下结果(只截取部分可以说明问题的截图,减小篇幅):


这里我们首先看到系统创建了十个进程。下面这张图你会看出十个进程阻塞在accept这个系统调用上面:


接下来在另一个终端执行telnet 127.0.0.1 1234:


很明显当telnet连接的时候只有一个进程accept成功,你会不会和我有同样的疑问,就是会不会内核中唤醒了所有的进程只是没有获取到资源失败了,就好像惊群被“隐藏”?

这个问题很好证明,我们修改一下代码:

                connfd = accept(fd, (struct sockaddr *)NULL, NULL);
if(connfd == 0){

snprintf(sendbuff, sizeof(sendbuff), "接收到accept事件的进程PID = %d\n", getpid());

send(connfd, sendbuff, strlen(sendbuff)+1, 0);
printf("process %d accept success\n", getpid());
close(connfd);
}else{
printf("process %d accept a connection failed: %s\n", getpid(), strerror(errno));
close(connfd);
}

没错,就是增加了一个accept失败的返回信息,按照上面的步骤运行,这里我就不截图了,我只告诉你运行结果与上面的运行结果无异,增加的失败信息并没有输出,也就说明了这里并没有发生惊群,所以注意阻塞和惊群的唤醒的区别。

其实在linux2.6版本以后,linux内核已经解决了accept()函数的“惊群”现象,大概的处理方式就是,当内核接收到一个客户连接后,只会唤醒等待队列上的第一个进程(线程),所以如果服务器采用accept阻塞调用方式,在最新的linux系统中已经没有“惊群效应”了

accept函数的惊群解决了,下面来让我们看看存在惊群现象的另一种情况:epoll惊群

*2)epoll惊群:

概述:

如果多个进程/线程阻塞在监听同一个监听socket fd的epoll_wait上,当有一个新的连接到来时,所有的进程都会被唤醒。

同样让我们假设一个场景:

主进程创建socket,bind,listen后,将该socket加入到epoll中,然后fork出多个子进程,每个进程都阻塞在epoll_wait上,如果有事件到来,则判断该事件是否是该socket上的事件如果是,说明有新的连接到来了,则进行接受操作。为了简化处理,忽略后续的读写以及对接受返回的新的套接字的处理,直接断开连接。

那么,当新的连接到来时,是否每个阻塞在epoll_wait上的进程都会被唤醒呢?

很多博客中提到,测试表明虽然epoll_wait不会像接受那样只唤醒一个进程/线程,但也不会把所有的进程/线程都唤醒。

这究竟是为什么呢?

我们还是眼见为实,一步步解决上面的疑问:

代码实例:epoll_thunder_herd.c:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PROCESS_NUM 10
#define MAXEVENTS 64
//socket创建和绑定
int sock_creat_bind(char * port){
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(port));
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(sock_fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
return sock_fd;
}
//利用fcntl设置文件或者函数调用的状态标志
int make_nonblocking(int fd){
int val = fcntl(fd, F_GETFL);
val |= O_NONBLOCK;
if(fcntl(fd, F_SETFL, val) < 0){
perror("fcntl set");
return -1;
}
return 0;
}

int main(int argc, char *argv[])
{
int sock_fd, epoll_fd;
struct epoll_event event;
struct epoll_event *events;

if(argc < 2){
printf("usage: [port] %s", argv[1]);
exit(1);
}
if((sock_fd = sock_creat_bind(argv[1])) < 0){
perror("socket and bind");
exit(1);
}
if(make_nonblocking(sock_fd) < 0){
perror("make non blocking");
exit(1);
}
if(listen(sock_fd, SOMAXCONN) < 0){
perror("listen");
exit(1);
}
if((epoll_fd = epoll_create(MAXEVENTS))< 0){
perror("epoll_create");
exit(1);
}
event.data.fd = sock_fd;
event.events = EPOLLIN;
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock_fd, &event) < 0){
perror("epoll_ctl");
exit(1);
}
/*buffer where events are returned*/
events = calloc(MAXEVENTS, sizeof(event));
int i;
for(i = 0; i < PROCESS_NUM; ++i){
int pid = fork();
if(pid == 0){
while(1){
int num, j;
num = epoll_wait(epoll_fd, events, MAXEVENTS, -1);
printf("process %d returnt from epoll_wait\n", getpid());
sleep(2);
for(i = 0; i < num; ++i){
if((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))){
fprintf(stderr, "epoll error\n");
close(events[i].data.fd);
continue;
}else if(sock_fd == events[i].data.fd){
//收到关于监听套接字的通知,意味着一盒或者多个传入连接
struct sockaddr in_addr;
socklen_t in_len = sizeof(in_addr);
if(accept(sock_fd, &in_addr, &in_len) < 0){
printf("process %d accept failed!\n", getpid());
}else{
printf("process %d accept successful!\n", getpid());
}
}
}
}
}
}
wait(0);
free(events);
close(sock_fd);
return 0;
}

上面的代码编译gcc epoll_thunder_herd.c -o server

一个终端运行代码 ./server 1234 另一个终端telnet 127.0.0.1 1234

运行结果:


这里我们看到只有一个进程返回了,似乎并没有惊群效应,让我们用strace -f ./server 8888追踪执行过程(这里只给出telnet之后的截图,之前的截图参考accept,不同的就是进程阻塞在epoll_wait)

截图(部分):


运行结果显示了部分个进程被唤醒了,返回了“process accept failed”只是后面因为某些原因失败了。所以这里貌似存在部分“惊群”。

怎么判断发生了惊群呢?

我们根据strace的返回信息可以确定:

1)系统只会让一个进程真正的接受这个连接,而剩余的进程会获得一个EAGAIN信号。图中有体现。

2)通过返回结果和进程执行的系统调用判断。

这究竟是什么原因导致的呢?

看我们的代码,看似部分进程被唤醒了,而事实上其余进程没有被唤醒的原因是因为某个进程已经处理完这个事件,无需唤醒其他进程,你可以在epoll获知这个事件的时候sleep(2);这样所有的进程都会被唤起。看下面改正后的代码结果更加清晰:

代码修改:

                num = epoll_wait(epoll_fd, events, MAXEVENTS, -1);
printf("process %d returnt from epoll_wait\n", getpid());
sleep(2);

运行结果:


如图所示:所有的进程都被唤醒了。所以epoll_wait的惊群确实存在。

为什么内核处理了accept的惊群,却不处理epoll_wait的惊群呢?

我想,应该是这样的:

accept确实应该只能被一个进程调用成功,内核很清楚这一点。但epoll不一样,他监听的文件描述符,除了可能后续被accept调用外,还有可能是其他网络IO事件的,而其他IO事件是否只能由一个进程处理,是不一定的,内核不能保证这一点,这是一个由用户决定的事情,例如可能一个文件会由多个进程来读写。所以,对epoll的惊群,内核则不予处理。

*3)线程惊群:

进程的惊群已经介绍的很详细了,这里我就举一个线程惊群的简单例子,我就截取上次红包代码中的代码片段,如下

        printf("初始的红包情况:<个数:%d  金额:%d.%02d>\n",item.number, item.total/100, item.total%100);
pthread_cond_broadcast(&temp.cond);//红包包好后唤醒所有线程抢红包
pthread_mutex_unlock(&temp.mutex);//解锁
sleep(1);

没错你可能已经注意到了,pthread_cond_broadcast()在资源准备好以后,或者你再编写程序的时候设置的某个事件满足时它会唤醒队列上的所有线程去处理这个事件,但是只有一个线程会真正的获得事件的“控制权”。

解决方法之一就是加锁。下面我们来看一看解决或者避免惊群都有哪些方法?

4.我们怎么解决“惊群”呢?你有什么高见?

这里通常代码加锁的处理机制我就不详述了,来看一下常见软件的处理机制和linux最新的避免和解决的办法

(1)、Nginx的解决:

如上所述,如果采用epoll,则仍然存在该问题,nginx就是这种场景的一个典型,我们接下来看看其具体的处理方法。

nginx的每个worker进程都会在函数
ngx_process_events_and_timers()中处理不同的事件,然后通过ngx_process_events()封装了不同的事件处理机制,在Linux上默认采用epoll_wait()。

在主要
ngx_process_events_and_timers()函数中解决惊群现象。

void ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
... ...
// 是否通过对accept加锁来解决惊群问题,需要工作线程数>1且配置文件打开accetp_mutex
if (ngx_use_accept_mutex) {
// 超过配置文件中最大连接数的7/8时,该值大于0,此时满负荷不会再处理新连接,简单负载均衡
if (ngx_accept_disabled > 0) {
ngx_accept_disabled--;
} else {
// 多个worker仅有一个可以得到这把锁。获取锁不会阻塞过程,而是立刻返回,获取成功的话
// ngx_accept_mutex_held被置为1。拿到锁意味着监听句柄被放到本进程的epoll中了,如果
// 没有拿到锁,则监听句柄会被从epoll中取出。
if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
return;
}
if (ngx_accept_mutex_held) {
// 此时意味着ngx_process_events()函数中,任何事件都将延后处理,会把accept事件放到
// ngx_posted_accept_events链表中,epollin|epollout事件都放到ngx_posted_events链表中
flags |= NGX_POST_EVENTS;
} else {
// 拿不到锁,也就不会处理监听的句柄,这个timer实际是传给epoll_wait的超时时间,修改
// 为最大ngx_accept_mutex_delay意味着epoll_wait更短的超时返回,以免新连接长时间没有得到处理
if (timer == NGX_TIMER_INFINITE || timer > ngx_accept_mutex_delay) {
timer = ngx_accept_mutex_delay;
}
}
}
}
... ...
(void) ngx_process_events(cycle, timer, flags); // 实际调用ngx_epoll_process_events函数开始处理
... ...
if (ngx_posted_accept_events) { //如果ngx_posted_accept_events链表有数据,就开始accept建立新连接
ngx_event_process_posted(cycle, &ngx_posted_accept_events);
}

if (ngx_accept_mutex_held) { //释放锁后再处理下面的EPOLLIN EPOLLOUT请求
ngx_shmtx_unlock(&ngx_accept_mutex);
}

if (delta) {
ngx_event_expire_timers();
}

ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "posted events %p", ngx_posted_events);
// 然后再处理正常的数据读写请求。因为这些请求耗时久,所以在ngx_process_events里NGX_POST_EVENTS标
// 志将事件都放入ngx_posted_events链表中,延迟到锁释放了再处理。
}}

(2)、SO_REUSEPORT

Linux内核的3.9版本带来了SO_REUSEPORT特性,该特性支持多个进程或者线程绑定到同一端口,提高服务器程序的性能,允许多个套接字bind()以及listen()同一个TCP或UDP端口,并且在内核层面实现负载均衡。

在未开启SO_REUSEPORT的时候,由一个监听socket将新接收的连接请求交给各个工作者处理,看图示:


在使用SO_REUSEPORT后,多个进程可以同时监听同一个IP:端口,然后由内核决定将新链接发送给哪个进程,显然会降低每个工人接收新链接时锁竞争


下面让我们好好比较一下多进程(线程)服务器编程传统方法和使用SO_REUSEPORT的区别

运行在Linux系统上的网络应用程序,为了利用多核的优势,一般使用以下典型的多进程(多线程)服务器模型:

1.单线程listener/accept,多个工作线程接受任务分发,虽然CPU工作负载不再成为问题,但是仍然存在问题:

(1)、单线程listener(图一),在处理高速率海量连接的时候,一样会成为瓶颈

(2)、cpu缓存行丢失套接字结构现象严重。

2.所有工作线程都accept()在同一个服务器套接字上呢?一样存在问题:

(1)、多线程访问server socket锁竞争严重。

(2)、高负载情况下,线程之间的处理不均衡,有时高达3:1。

(3)、导致cpu缓存行跳跃(cache line bouncing)。

(4)、在繁忙cpu上存在较大延迟。

上面两种方法共同点就是很难做到cpu之间的负载均衡,随着核数的提升,性能并没有提升。甚至服务器的吞吐量CPS(Connection Per Second)会随着核数的增加呈下降趋势。

下面我们就来看看SO_REUSEPORT解决了什么问题:

(1)、允许多个套接字bind()/listen()同一个tcp/udp端口。每一个线程拥有自己的服务器套接字,在服务器套接字上没有锁的竞争。

(2)、内核层面实现负载均衡

(3)、安全层面,监听同一个端口的套接字只能位于同一个用户下面。

(4)、处理新建连接时,查找listener的时候,能够支持在监听相同IP和端口的多个sock之间均衡选择。

当一个连接到来的时候,系统到底是怎么决定那个套接字来处理它?

对于不同内核,存在两种模式,这两种模式并不共存,一种叫做热备份模式,另一种叫做负载均衡模式,3.9内核以后,全部改为负载均衡模式。

热备份模式:一般而言,会将所有的reuseport同一个IP地址/端口的套接字挂在一个链表上,取第一个即可,工作的只有一个,其他的作为备份存在,如果该套接字挂了,它会被从链表删除,然后第二个便会成为第一个。

负载均衡模式:和热备份模式一样,所有reuseport同一个IP地址/端口的套接字会挂在一个链表上,你也可以认为是一个数组,这样会更加方便,当有连接到来时,用数据包的源IP/源端口作为一个HASH函数的输入,将结果对reuseport套接字数量取模,得到一个索引,该索引指示的数组位置对应的套接字便是工作套接字。这样就可以达到负载均衡的目的,从而降低某个服务的压力。

end



一口Linux 


关注,回复【1024】海量Linux资料赠送


精彩文章合集

文章推荐

【专辑】ARM
【专辑】粉丝问答
【专辑】所有原创
专辑linux入门
专辑计算机网络
专辑Linux驱动
【干货】嵌入式驱动工程师学习路线
【干货】Linux嵌入式所有知识点-思维导图

一口Linux 写点代码,写点人生!
评论 (0)
  • 一、技术背景与市场机遇在智能家居高速发展的今天,用户对家电设备的安全性、智能化及能效表现提出更高要求。传统取暖器因缺乏智能感知功能,存在能源浪费、安全隐患等痛点。WTL580-C01微波雷达感应模块的诞生,为取暖设备智能化升级提供了创新解决方案。该模块凭借微波雷达技术优势,在精准测距、环境适应、能耗控制等方面实现突破,成为智能取暖器领域的核心技术组件。二、核心技术原理本模块采用多普勒效应微波雷达技术,通过24GHz高频微波信号的发射-接收机制,实现毫米级动作识别和精准测距。当人体进入4-5米有效
    广州唯创电子 2025-04-23 08:41 123浏览
  • 文/Leon编辑/cc孙聪颖‍4月18日7时,2025北京亦庄半程马拉松暨人形机器人半程马拉松正式开跑。与普通的半马比赛不同,这次比赛除了有人类选手,还有21支人形机器人队伍参赛,带来了全球首次人类与机器人共同竞技的盛况。参赛队伍中,不乏明星机器人企业及机型,比如北京人形机器人创新中心的天工Ultra、松延动力的N2等。宇树G1、众擎PM01,则是由城市之间科技有限公司购置及调试,并非厂商直接参赛。考虑到机器人的适用场景和续航力各有不同,其赛制也与人类选手做出区别:每支赛队最多可安排3名参赛选手
    华尔街科技眼 2025-04-22 20:10 112浏览
  • 一、行业背景与市场需求高血压作为全球发病率最高的慢性病之一,其早期监测与管理已成为公共卫生领域的重要课题。世界卫生组织数据显示,全球超13亿人受高血压困扰,且患者群体呈现年轻化趋势。传统血压计因功能单一、数据孤立等缺陷,难以满足现代健康管理的需求。在此背景下,集语音播报、蓝牙传输、电量检测于一体的智能血压计应运而生,通过技术创新实现“测量-分析-管理”全流程智能化,成为慢性病管理的核心终端设备。二、技术架构与核心功能智能血压计以电子血压测量技术为基础,融合物联网、AI算法及语音交互技术,构建起多
    广州唯创电子 2025-04-23 09:06 143浏览
  •   电磁频谱数据综合管理平台系统解析   一、系统定义与目标   北京华盛恒辉电磁频谱数据综合管理平台融合无线传感器、软件定义电台等前沿技术,是实现无线电频谱资源全流程管理的复杂系统。其核心目标包括:优化频谱资源配置,满足多元通信需求;运用动态管理与频谱共享技术,提升资源利用效率;强化频谱安全监管,杜绝非法占用与干扰;为电子战提供频谱监测分析支持,辅助作战决策。   应用案例   目前,已有多个电磁频谱数据综合管理平台在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁频谱数
    华盛恒辉l58ll334744 2025-04-23 16:27 148浏览
  •   后勤实验仿真系统平台深度解析   北京华盛恒辉后勤实验仿真系统平台依托计算机仿真技术,是对后勤保障全流程进行模拟、分析与优化的综合性工具。通过搭建虚拟场景,模拟资源调配、物资运输等环节,为后勤决策提供数据支撑,广泛应用于军事、应急管理等领域。   应用案例   目前,已有多个后勤实验仿真系统平台在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润后勤实验仿真系统平台。这些成功案例为后勤实验仿真系统平台的推广和应用提供了有力支持。   一、核心功能   (一)后勤资源模拟
    华盛恒辉l58ll334744 2025-04-23 15:39 118浏览
  •   陆地边防事件紧急处置系统平台解析   北京华盛恒辉陆地边防事件紧急处置系统平台是整合监测、预警、指挥等功能的智能化综合系统,致力于增强边防安全管控能力,快速响应各类突发事件。以下从系统架构、核心功能、技术支撑、应用场景及发展趋势展开全面解读。   应用案例   目前,已有多个陆地边防事件紧急处置系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润陆地边防事件紧急处置系统。这些成功案例为陆地边防事件紧急处置系统的推广和应用提供了有力支持。   一、系统架构   感知层:部
    华盛恒辉l58ll334744 2025-04-23 11:22 113浏览
  • 在科技飞速发展的当下,机器人领域的每一次突破都能成为大众瞩目的焦点。这不,全球首届人形机器人半程马拉松比赛刚落下帷幕,赛场上的 “小插曲” 就掀起了一阵网络热潮。4月19日,北京亦庄的赛道上热闹非凡,全球首届人形机器人半程马拉松在这里激情开跑。20支机器人队伍带着各自的“参赛选手”,踏上了这21.0975公里的挑战之路。这场比赛可不简单,它将机器人放置于真实且复杂的动态路况与环境中,对机器人在运动控制、环境感知和能源管理等方面的核心技术能力进行了全方位的检验。不仅要应对长距离带来的续航挑战,还要
    用户1742991715177 2025-04-22 20:42 98浏览
  •   卫星通信效能评估系统平台全面解析   北京华盛恒辉卫星通信效能评估系统平台是衡量卫星通信系统性能、优化资源配置、保障通信服务质量的关键技术工具。随着卫星通信技术的快速发展,特别是低轨卫星星座、高通量卫星和软件定义卫星的广泛应用,效能评估系统平台的重要性日益凸显。以下从技术架构、评估指标、关键技术、应用场景及发展趋势五个维度进行全面解析。   应用案例   目前,已有多个卫星通信效能评估系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润卫星通信效能评估系统。这些成功案例为卫
    华盛恒辉l58ll334744 2025-04-22 16:34 148浏览
  • 文/Leon编辑/cc孙聪颖‍在特朗普政府发起的关税战中,全球芯片产业受到巨大冲击,美国芯片企业首当其冲。据报道称,英伟达本周二公布的8-K文件显示,美国政府通知该公司向中国(包括中国香港及澳门)销售尖端芯片(H20)时,需要获得美国政府的许可。文件发布后,英伟达预计会在第一季度中额外增加55亿美元的相关费用计提。随后,英伟达股价单日下跌6.9%,市值一夜蒸发约1890亿美元(约合人民币1.37万亿元)。至截稿时,至截稿时,其股价未见止跌,较前日下跌4.51%。北京时间4月17日,英伟达创始人、
    华尔街科技眼 2025-04-22 20:14 106浏览
  • 故障现象一辆2016款奔驰C200L车,搭载274 920发动机,累计行驶里程约为13万km。该车组合仪表上的防侧滑故障灯、转向助力故障灯、安全气囊故障灯等偶尔异常点亮,且此时将挡位置于R挡,中控显示屏提示“后视摄像头不可用”,无法显示倒车影像。 故障诊断用故障检测仪检测,发现多个控制单元中均存储有通信类故障代码(图1),其中故障代码“U015587 与仪表盘的通信存在故障。信息缺失”出现的频次较高。 图1 存储的故障代码1而组合仪表中存储有故障代码“U006488 与用户界
    虹科Pico汽车示波器 2025-04-23 11:22 83浏览
  •   无人机结构仿真与部件拆解分析系统平台解析   北京华盛恒辉无人机结构仿真与部件拆解分析系统无人机技术快速发展的当下,结构仿真与部件拆解分析系统平台成为无人机研发测试的核心工具,在优化设计、提升性能、降低成本等方面发挥关键作用。以下从功能、架构、应用、优势及趋势展开解析。   应用案例   目前,已有多个无人机结构仿真与部件拆解分析系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润无人机结构仿真与部件拆解分析系统。这些成功案例为无人机结构仿真与部件拆解分析系统的推广和应用提
    华盛恒辉l58ll334744 2025-04-23 15:00 154浏览
  • 前言本文主要演示基于TL3576-MiniEVM评估板HDMI OUT、DP 1.4和MIPI的多屏同显、异显方案,适用开发环境如下。Windows开发环境:Windows 7 64bit、Windows 10 64bitLinux开发环境:VMware16.2.5、Ubuntu22.04.5 64bitU-Boot:U-Boot-2017.09Kernel:Linux-6.1.115LinuxSDK:LinuxSDK-[版本号](基于rk3576_linux6.1_release_v
    Tronlong 2025-04-23 13:59 101浏览
  •   复杂电磁环境模拟系统平台解析   一、系统概述   北京华盛恒辉复杂电磁环境模拟系统平台是用于还原真实战场或特定场景电磁环境的综合性技术平台。该平台借助软硬件协同运作,能够产生多源、多频段、多体制的电磁信号,并融合空间、时间、频谱等参数,构建高逼真度的电磁环境,为电子对抗、通信、雷达等系统的研发、测试、训练及评估工作提供重要支持。   应用案例   目前,已有多个复杂电磁环境模拟系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润复杂电磁环境模拟系统。这些成功案例为复杂电
    华盛恒辉l58ll334744 2025-04-23 10:29 154浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦