《LKD3粗读笔记》(11)定时器和时间管理

news2024/11/27 2:20:50

文章目录

    • 1、内核中的时间概念
    • 2、 节拍率:HZ
    • 3、jiffies
    • 4、硬时钟和定时器
    • 5、时钟中断处理程序
    • 6、实际时间
    • 7、定时器
    • 8、延迟执行

1、内核中的时间概念

  • 硬件为内核提供了一个系统定时器用以计算流逝的时间,该时钟在内核中可看成是一个电子时间资源,比如数字时钟或处理器频率等。
  • 系统定时器以某种频率自行触发(常被称为击中(hitting)或者射中(popping))时钟中断,该频率可以通过编程预定,称作节拍率(tick rate)。
  • 内核维护两种时间:墙上时间系统运行时间
  • 什么是墙上时间?
    墙上时间也就是实际时间,对用户空间的应用程序来说是最重要的。
  • 什么是系统运行时间?
    系统运行时间也就是自系统启动开始所经的时间,对用户空间和内核都很有用。
  • 这两种时间内核如何维护计算?
    通过预编的节拍率可以知道连续两次时钟中断的间隔时间(节拍(tick))。 这个间隔时间等于节拍率分之一(1/(tick rate))秒。
  • 利用时钟中断周期执行的任务有哪些?
    注意:有些工作随时钟频率反复执行,有些是n个时钟中断执行一次。
    • 更新系统运行时间
    • 更新实际时间
    • 在SMP上,均衡调度程序尽量使运行队列负载均衡
    • 检查当前进程是否用尽了自己的时间片
    • 运行超时的动态定时器
    • 更新资源消耗和处理器时间统计值
  • 言下之意,还有一些工作不是周期执行的,但依旧需要使用时间管理资源。

2、 节拍率:HZ

  • 系统定时器频率(节拍率)通过静态预处理定义,也就是HZ(赫兹),在asm/param.h文件中定义了这个值。与体系结构有关。
  • 例如:在x86体系结构中,系统定时器频率默认为100。因此,x86上时钟中断的频率就是100HZ,也就是说每秒时钟中断100次,即每10ms中断一次
  • HZ值不是一个固定不变的值,大多数体系结构的节拍率是可调的
  • 下面是各种体系结构与之对应的时钟中断频率
    在这里插入图片描述
  • 高HZ值的优势是什么?
    • 内核定时器能够以更高的频度更高的准确度运行;
    • 依赖定时值执行的系统调用,比如poll()select(),能够以更高的精度运行;
    • 提高进程抢占的准确度
  • 高HZ值的劣势是什么?
    • 系统负担变重,中断处理程序占用处理器时间越多,处理其他任务时间减少
    • 频繁打乱处理器高速缓存,增加耗电
  • 无节拍的OS
    • Linux内核支持“无节拍操作”选项。编译内核时设置了CONFIG_HZ配置选项,系统根据这个选项动态调度时钟中断,不是固定间隔。
    • 例如:如果50ms内无事可做,内核以50ms重新调度时钟中断。

3、jiffies

  • 全局变量jiffies用来记录自系统启动以来产生的节拍的总数。
  • jiffies定义于文件<linux/jiffies.h>中,存放jiffies类型数据的时候必须用无符号长整型(unsigned long):
    extern unsigned long volatile jiffies;
    
  • 将以秒为单位的时间转化为jiffies
    (seconds * HZ)
    
  • jiffies转化为以秒为单位的时间:
    (jiffies/HZ)
    
  • 设置将来的时间:
    unsigned long time_stamp = jiffies; 		/*现在*/
    unsigned long next_tick = jiffies+1;		/*从现在开始1个节拍*/
    unsigned long later = jiffies+5*HZ;			/*从现在开始5秒*/
    unsigned long fraction = jiffies + HZ / 10;	/*从现在开始1/10秒*/
    
  1. jiffies的内部表示
    • jiffies变量总是unsigned long类型,在32位上是32位,在64位上是64位。因为32位jiffies会溢出,所以需要引入64位的jiffies_64
    • jiffies_64定义在<linux/jiffies.h>中:
      extern u64 jiffies_64;
      jiffies = jiffies_64; //非常巧妙
      
      这样一来,在32位机器中,访问jiffies等价于访问jiffies_64的低32位;而在64位机器中,访问jiffies则等价于访问jiffies_64
    • 下面是jiffiesjiffies_64的划分,对照前一句话进行理解。
      在这里插入图片描述
  2. jiffies的回绕
    • 什么是回绕?
      和任何C整型一样,当jiffies变量的值超过它的最大存放范围后就会发生溢出。即:对于32位无符号长整型,最大取值为2^32-1。所以在溢出前,定时器节拍计数最大为4294967295。当节拍计数达到了最大值后还要继续增加,那jiffies的值会回绕到0
    • 内核提供如下宏来帮助比较节拍计数,以便能够正确处理节拍计数回绕情况,定义在文件<linux/jiffies.h>中。简化版如下:
      #define time_after(unknown,known) ((long)(known) - (long)(unknown) < 0)
      #define time_before(unknown,known) ((long)(unknown) - (long)(known) < 0)
      #define time_after_eq(unknown,known) ((long)(unknown) - (long)(known) >= 0)
      #define time_before_eq(unknown,known) ((long)(known) - (long)(unknown) >= 0)
      
      其中unknown参数通常是jiffiesknown参数是需要对比的值。
    • 一个回绕的例子
      unsigned long timeout = jiffies + HZ/2; /*0.5秒后超时*/
      //if(timeout > jiffies){//没有使用正确处理回绕的宏,那么就会发生错误
      if(time_before(jiffies,timeout)){ //使用了正确处理回绕的宏
      	/*没有超时,很好*/
      }else{
      	/*超时了,发生错误*/
      }
      
  3. 用户空间和HZ
    • 在Linux 2.6以前的版本中,改变内核的HZ值会影响用户空间的某些程序。
    • USER_HZ代表用户空间看到的HZ,用 jiffies_to_clock_t()HZ转换成USER_HZ表示的节拍数。

4、硬时钟和定时器

  1. RTC
    • 什么是实时时钟(RTC)?
      实时时钟是用来持久存放系统时间的设备,即便系统关闭后,它也可以靠主板上的微型电池提供的电力保持系统的计时
    • RTC对内核的作用是什么?
      当系统启动时,内核通过读取RTC来初始化墙上时间,该时间存放在xtime变量中。
  2. 系统定时器
    • 系统定时器的根本思想是提供一种周期性触发中断机制
    • 有对晶振分频实现定时器的,也有衰减值定时的。
    • x86中主要采用可编程中断时钟(PIT),还有其他的时钟资源如本地APIC时钟和时间戳计数(TSC)等。

5、时钟中断处理程序

  • 时钟中断处理程序可以划分哪两个部分?
    体系结构相关体系结构无关部分。
  • 与体系结构相关的部分做哪些工作?
    与体系结构相关的部分作为系统定时器中断处理程序而注册到内核中,以便在产生时钟中断时,它能够相应的运行。处理程序的具体工作依赖于特定的体系结构,最少需要执行以下操作:
    • 获得xtime_lock锁,以便对访问jiffies_64和墙上时间xtime进行保护;
    • 需要时应答或重新设置系统时钟
    • 周期性地使用墙上时间更新实时时钟
    • 调用体系结构无关的时钟部分:tick_perodic()
  • tick_perodic()函数做什么工作?
    • jiffies_64变量增加1(这个操作即使是在32位体系结构上也是安全的,因为前面已经获得了xtime_lock锁);
    • 更新资源消耗的统计值,比如当前进程所消耗的系统时间用户时间
    • 执行已经到期的动态定时器
    • 执行sheduler_tick()函数(负责减少当前运行进程的时间片计数值并且设置need_resched标志);
    • 更新墙上时间,该时间存放在xtime变量中;
    • 计算平均负载值。
      注意:以上全部工作每1/HZ秒都要发生一次,可以联想STM32的中断服务程序

6、实际时间

  • 实际时间(墙上时间)的定义
    • 定义在文件kernel/time/timekeeping.c中:
      struct timespec xtime;
      
    • timespec数据结构定义在文件<linux/time.h>中,形式如下:
      struct timespec{
      	_kernel_time_t tv_sec;		/* 以s为单位,存放着自1970年1月1日(UTC)以来经过的时间,1970年1月1日被称为纪元。*/
      	long tv_nsec;				/* 记录自上一秒开始经过的ns数 */
      };
      
  • 读写xtime变量需要有哪些操作?
    • xtime首先需要申请一个seqlock锁:
      write_seqlock(&xtime_lock);
      /*更新xtime*/
      write_unseqlock(&xtime_lock);
      
    • xtime也要使用read_seqbegin()read_seqretry()函数
      /* 顺序锁中读锁来循环获取 xtime,直至读取过程中 xtime 没有被改变过 */
          do {
              seq = read_seqbegin(&xtime_lock);
      
              *ts = xtime;
              nsecs = timekeeping_get_ns();
      
              /* If arch requires, add in gettimeoffset() */
              nsecs += arch_gettimeoffset();
      
          } while (read_seqretry(&xtime_lock, seq));
      /* 省略 。。。。 */
      }
      
      该循环不断重复,如果发现循环期间有时间中断处理程序更新xtime,那么read_seqretry()函数就返回无效序列号,继续循环等待。
    • 关注一下使用顺序锁而非普通锁的原因。
      • 写时间的进程少,读时间的进程多。
      • 希望写进程优先于读进程(显而易见,写时间延迟的话会造成很大问题),而且不允许读者让写着饥饿。
  • 如何从用户空间得到墙上时间?
    从用户空间取得墙上时间的主要接口是gettimeofday(),在内核中对应的系统调用是sys_gettimeofday(),定义于kernel/time.c中。它实现的逻辑是:
    • 如果用户提供的tv参数非空,那么与体系结构相关的do_gettimeofday()函数将被调用;
    • 如果tz参数为空,该函数就把系统时区返回用户。
  • 用户如何设置当前时间?
    • 使用系统调用settimeofday()

7、定时器

  • 什么是定时器?
    定时器也称作为动态定时器内核定时器,它是管理内核流逝时间的基础
  • 定时器有什么作用?
    例如:内核经常需要推后执行某些代码,而使用定时器就可以执行推后执行的工作。
  • 如何使用定时器?
    • 分为四步:1. 执行初始化工作;2. 设置超时时间;3. 指定超时发生执行的函数;4.激活定时器。
    • 注意:指定的函数会在定时器到期自动执行,定时器不周期运行,在超时后就自行撤销
  1. 使用定时器

    • 定时器的定义
      定时器结构由timer_list 表示,在linux/timer.h中。
      struct timer_list {
      	struct list_head entry; 		 /* 定时器链表的入口 */
      	unsigned long expires; 			 /* 以jiffies为单位的定时值 */
      	void (*function)(unsigned long); /* 定时器处理函数 */
      	unsigned long data; 			 /* 传递给处理函数的参数 */
      	struct tvec_t_base_s *base; 	 /* 定时器内部值,用户不要使用 */
      };
      
    • 定时器相关的接口
      与定时器相关的接口,声明在linux/timer.h,实现在kernel/timer.c, 需要注意的是,内核可能延误一个节拍才执行处理函数,所有任何硬实时任务都不能用它。
      • 定义定时器结构
        struct timer_list my_timer;
        
      • 初始化定时器数据结构的内部值
        init_timer(&my_timer);
        
      • 填充数据
        my_timer.expires = jiffies + delay; /* 定时器超时时间节拍数 */
        my_timer.data = 0; 					/* 该参数可使用户利用同一个处理函数注册多个定时器,不需要则传递0或其他任何值 */
        my_timer.function = my_function; 	/* 定时器超时处理函数 */
        
      • 激活定时器
        add_timer(&my_timer);
        
      • 更改定时器超时时间
        // 改变超时时间,如果定时器没被激活,则自动激活。之前未激活返回0 ,激活返回1
        mod_timer(&my_timer, jiffies + new_delay); /* 新的定时值 */
        
      • 在定时器超时之前删除定时器
        // 在还未超时时可以删除定时器,
        // 激活未激活的都行(未激活返回0,否则返回1),但是超时就不用了因为已经自动删除了
        del_timer(&my_timer); 	/* 能在中断上下文使用 */
        
        // 删除定时器存在潜在竞争条件,删除定时器时可能要等待其他处理器上运行的定时器处理程序都退出
        // 该函数不能在中断上下文中使用,因为它会造成睡眠。
        del_timer_sync(&my_timer); /* 不能在中断上下文中使用,但优先使用*/
        
  2. 定时器竞争条件

    • 定时器与当前执行代码是异步的,可能存在潜在的竞争条件。以删除定时器为例,最好使用del_timer_sync()而非del_timer()
    • 还要着重保护定时器中断处理程序中的共享数据
  3. 实现定时器

    • 什么时候执行定时器?
      内核在时钟中断发生后执行定时器,定时器作为软中断在下半部上下文中执行。
    • 执行定时器的步骤是什么?
      时钟中断处理程序会执行update_process_times(),然后调用run_local_timers()run_local_timers函数处理软中断TIMER_SOFTIRQ,从而在当前处理器上运行所有的超时定时器。
      void run_local_timers(void)
      {
      	hrtimer_run_queues();
      	raise_softirq(TIMER_SOFTIRQ); /* 执行定时器软中断 */
      	softlockup_tick();
      }
      
    • 搜索超时定时器的策略
      • 内核按照定时器的超时时间将定时器分为5组,超时时间相近的定时器为一组
      • 当定时器超时时间接近时,定时器将随组一起下移
    • 为什么需要上述策略?
      所有定时器以链表形式存放,寻找超时定时器而遍历链表是不明智的

8、延迟执行

  • 内核代码(尤其是驱动程序)除了使用定时器或下半部机制以外,还有其他方法推迟执行任务。这种延迟常用于等待硬件完成某些工作,而且等待时间非常短。 如重新设置以太网卡模式需要等待2ms
  • 内核提供多种延迟方法处理各种延迟要求,有些在延迟任务时挂起处理器,防止处理器执行任何实际工作;有些不会挂起处理器,所以也不能确保延迟代码能够在指定的延迟时间运行。
  1. 忙等待
    • 最简单不理想的方法
      延迟节拍的整数倍或者精确度要求不高的延时。例如:等待10个节拍,处理器原地旋转。
      unsigned long timeout = jiffies + 10; /* ten ticks */
      while (time_before(jiffies, timeout))
      	;
      
    • 更好的方法
      在代码等待时,允许内核重新调度其他任务。由于需要调度程序,不能在中断上下文中使用,只能在进程上下文中使用。例如:
      unsigned long delay = jiffies + 5*HZ;
      while (time_before(jiffies, delay))
      	cond_resched();  // cond_resched将调度一个新程序投入运行,但需要设置完need_resched标志后才可生效
      					 // 换句话说,系统中存在更重要的任务需要运行。
      
    • 延迟执行不应该持有锁时禁止中断时发生。
  2. 短延迟
    • 什么情况下使用短延迟?
      有时内核代码(通常时驱动程序)需要很短延迟而却要精确,多发生在与硬件同步时。大多小于1ms,因此不能用jiffies。内核提供三个可以处理msusns级别的延迟函数,定义在linux/delay.hasm/delay.h中。
      void udelay(unsigned long usecs)
      void ndelay(unsigned long nsecs)
      void mdelay(unsigned long msecs)
      
    • 什么是BogoMIPS
      BogoMIPS这一名字取自bogus(伪的)和MIPS(Million Instructions Per Second)。取该名字的原因是:它记录的并不是机器性能而是在给定时间内忙循环执行的次数,处理器在空闲时速度有多快。该值存放在变量loops_per_jiffy中,可以从文件/proc/cpuinfo中读到。该变量可以提供精确延迟需要进行的循环数。
  3. schedule_timeout()
  • 更理想的方法是使用schedule_timeout()函数,该方法会让需要延迟执行的任务睡眠到指定的延时时间耗尽后再重新运行

  • 睡眠时间不能保证等于指定的延时时间,只能尽量接近指定时间

  • 在调用shcedule_timeout时,任务必须设置状态为TASK_INTERRUPTIBLE或者TASK_UNINTERRUPTIBLE。例如:

    /* 将任务设置为可中断睡眠状态 */
    set_current_state(TASK_INTERRUPTIBLE);
    /* 小睡一会,"s"秒后唤醒 */
    schedule_timeout(s*HZ);
    
    1. schedule_timeout()的实现
      signed long schedule_timeout(signed long timeout)
      {
          time_t timer;//创建了一个定时器timer
          unsigned long expire;
      
          switch(timeout)
          {
          case MAX_SCHEDULE_TIMEOUT://任务无限期休眠,不允许!
              schedule();
              goto out;
          default:
              if(timeout < 0)//超时时间设置小于0,不允许!
              {
                  printk(KERN_ERR "schedule_timeout: wrong timeout "
                      "value %lx from %p\n", timeout,
                      __builtin_return_address(0));
                  current->state = TASK_RUNNING;
                  goto out;
              }
          }
          
          expire = timeout + jiffies;
      
          init_timer(&timer);
          timer.expires = expires;
          timer.data = (unsigned long)current;
          timer.function = process_timeout;//设置超时执行函数process_timeout()
      
          add_timer(&timer);//激活定时器
          schedule();//调用schedule()
          del_timer_sync(&timer);//任务提前被唤醒,定时器被撤销
      
          timeout = expire - jiffies;//剩余的时间
      
      out:
          return timeout < 0 ? 0 : timeout;
      }
      
    2. 设置超时时间,在等待队列上睡眠。
      等待队列中的任务可能既在等待一个特定事件到来,又在等待一个特定时间到期(取决于两者的速度)。在这种情况下,代码可以简单地使用schedule_timeout()函数代替schedule()函数。

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

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

相关文章

Nginx安装删除JDK Tomcat Redis

1.卸载Nginx ps -ef|grep nginx 查询Nginx 进程pid 如上图 master是主进程, worker是工作进程, master负责维护worker进程 Nginx启动后默认启动master进程和worker进程 Nginx默认使用端口80 kill -9 7035 或者 kill -term 7035 kill -9 7036 查找根下所有名字包…

带你搞懂人工智能、机器学习和深度学习!

不少高校的小伙伴找我聊入门人工智能该怎么起步&#xff0c;如何快速入门&#xff0c;多长时间能成长为中高级工程师&#xff08;聊下来感觉大多数学生党就是焦虑&#xff0c;毕业即失业&#xff0c;尤其现在就业环境这么差&#xff09;&#xff0c;但聊到最后&#xff0c;很多…

07 Kubernetes 网络与服务管理

课件 Kubernetes Service是一个抽象层&#xff0c;用于定义一组Pod的访问方式和访问策略&#xff0c;其作用是将一组Pod封装成一个服务&#xff0c;提供一个稳定的虚拟IP地址和端口号&#xff0c;以便于其他应用程序或服务进行访问。 以下是Kubernetes Service YAML配置文件的…

FPGA时序约束(五)衍生时钟约束与I/O接口约束

系列文章目录 FPGA时序约束&#xff08;一&#xff09;基本概念入门及简单语法 FPGA时序约束&#xff08;二&#xff09;利用Quartus18对Altera进行时序约束 FPGA时序约束&#xff08;三&#xff09;时序约束基本路径的深入分析 FPGA时序约束&#xff08;四&#xff09;主时…

2023五一建模A题完整版本【原创首发】

已经完成五一数学建模全部内容&#xff0c;大家可以文末查看&#xff01;&#xff01;供参考使用&#xff01; 摘要 本文研究了喷气式无人机在执行空中物资投放和爆破任务过程中的数学建模问题。我们分析了无人机投放距离与飞行高度、飞行速度、空气阻力等因素之间的关系&…

【Mybatis源码分析】动态标签的底层原理,DynamicSqlSource源码分析

DynamicSqlSource 源码分析 一、DynamicSqlSource 源码分析&#x1f62f;DynamicContext源码分析&#x1f644;SqlNode源码分析&#xff08;动态SQL标签&#xff09;Mybatis 动态SQL标签举例、调试SqlNode源码分析MixedSqlNodeIfSqlNodeWhereSqlNode、SetSqlNode、TrimSqlNodeS…

区域医疗云his系统源码,具有可扩展、易共享、易协同的优势

云HIS系统采用SaaS软件应用服务模式&#xff0c;提供软件应用服务多租户机制&#xff0c;实现一中心部署多机构使用。相对传统HIS单机构应用模式&#xff0c;它可灵活应对区域医疗、医疗集团、医联体、连锁诊所、单体医院等应用场景&#xff0c;并提升区域内应用的标准化与规范…

安装配置goaccess实现可视化并实时监控nginx的访问日志

一、业务需求 我们安装了nginx后,需要对nginx的访问情况进行监控(希望能够实时查看到访问nginx的情况),如下图所示: 二、goaccess的安装配置步骤 2.1、准备内容 需要先安装配置nginx或OpenResty - 安装 Linux环境对Nginx开源版源码下载、编译、安装、开机自启https://b…

从0开始利用Jenkins构建Maven项目(微服务)并自动发布

0. 前言 本文旨在帮助读者梳理如何从0开始利用Jenkins构建Maven项目&#xff08;微服务&#xff09;的自动发布任务 本文目录如下&#xff1a; 如何完成自动部署 0. 前言1. 配置工具类地址1.1 JDK1.2 Git1.3 Maven 2. 安装Jenkins3. 安装额外的工具插件4. 配置必要参数4.1 配…

TiDB实战篇-索引设计

简介 实战索引设计 数据映射原理 索引 唯一索引 二级索引 索引实例 索引设计 索引创建&#xff08;建表的时候创建&#xff09; 建表完以后添加 联合索引&#xff08;最左原则&#xff0c;索引覆盖&#xff09; 使用例子 索引覆盖 表达式索引 表达式索引的使用 不可见…

【youcans 的 OpenCV 学习课】23. 人脸检测:Haar 级联检测器

专栏地址&#xff1a;『youcans 的图像处理学习课』 文章目录&#xff1a;『youcans 的图像处理学习课 - 总目录』 【youcans 的 OpenCV 学习课】23. 人脸检测&#xff1a;Haar 级联检测器 4. Haar 级联分类器5. Haar 人脸/人眼检测器5.1 OpenCV 中的级联分类器5.2 Haar 级联检…

OPNET Modeler 调试简介

在使用 OPNET Modeler 软件运行仿真时&#xff0c;经常会遇到错误&#xff0c;发现和定位错误所在的地方是解决错误的第一步&#xff0c;那么怎么定位错误呢&#xff0c;这个时候就需要采用仿真调试器 (OPNET Simulation Debugger&#xff0c;ODB)进行调试了。 在 OPNET 中&…

【模电实验】电路元件伏安特性的测绘及电源外特性的测量

实验2电路元件伏安特性的测绘及电源外特性的测量 实验目的 学习测量线性和非线性电阻元件伏安特性的方法&#xff0c;并绘制其特性曲线学习测量电源外特性的方法掌握运用伏安法判定电阻元件类型的方法学习使用直流电压表、电流表&#xff0c;掌握电压、电流的测量方法 实验原…

Java BIO(Blocking IO:同步并阻塞式IO)

1.基本介绍 1>.Java BIO就是传统的java io编程,其相关的类和接口在"java.io"包下; 2>.BIO(Blocking I/O): 同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理; 如果这个连接不做任何事情会造成(服务器)不必…

【C++】STL——list深度剖析 及 模拟实现

文章目录 前言1. list的介绍及使用1.1 list的介绍1.2 list的使用遍历插入删除数据Operations迭代器的功能分类list 的sort性能测试 2. list的模拟实现2.1 STL_list源码浏览2.2 基本结构实现2.3 思考&#xff1a;list迭代器是否可以用原生指针2.4 list迭代器的实现&#xff08;重…

RocketMQ5.1 NameServer 路由管理

文章目录 1. 路由管理核心组件介绍2. RouteInfoManager 路由表3. 路由管理3.1 注册 Broker3.2 注销 Broker3.3 拼凑 TopicRouteData 此文章基于 RocketMQ 5.1 版本进行分析&#xff0c;与 4.x 版本相比此文章分析的部分源码有很大的区别 1. 路由管理核心组件介绍 路由管理是指…

亚马逊、沃尔玛、ebay测评出现风控、砍单、封号怎么解决?

大家好&#xff0c;我是亚马逊测评珑哥&#xff0c;提前祝各位跨境朋友五一假期愉快。 很多卖家和工作室的朋友加珑哥&#xff0c;沟通中很多朋友都在问为什么测评中一直被砍单&#xff0c;封号是什么原因&#xff1f;其实测评不是你随便买个IP&#xff0c;或者买几个买家号就…

轻松掌握mysql慢查询定位与优化知识点

在这里插入图片描述 1、利用工具定位慢sql 1、运维工具Skywalking 1、定位到慢接口 2、追踪慢sql的执行情况 2、利用MySQL的日志定位慢sql 在调式阶段才开启慢日志的查询&#xff0c;因为会损耗一些性能。 3、分析是否正确使用了索引 当我们已经定位到具体哪个sql较慢时&…

【计算几何】帝国边界划分问题【Voronoi图的原理】

一、说明 Voronoi 单元也称为泰森多边形。 Voronoi 图在许多领域都有实际和理论应用&#xff0c;主要是在科学和技术领域&#xff0c;但也在视觉艺术领域使用。Voronoi 图以数学家 Georgy Voronoy 的名字命名&#xff0c;也称为 Voronoi 镶嵌、Voronoi 分解、Voronoi 分区或 Di…

减少过拟合:暂退法

文章目录 &#xff08;一&#xff09;过拟合&#xff08;二&#xff09;暂退法 &#xff08;一&#xff09;过拟合 1.过拟合产生的原因 (1)根本原因&#xff1a; 我们都知道模型参数的优化方式&#xff1a;反向传播更新梯度&#xff0c;然后随机梯度下降。 也非常清楚模型参…