iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >React中的任务调度算法是什么
  • 780
分享到

React中的任务调度算法是什么

2024-04-02 19:04:59 780人浏览 独家记忆
摘要

这篇文章主要讲解了“React中的任务调度算法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“React中的任务调度算法是什么”吧!React中的任务池

这篇文章主要讲解了“React中的任务调度算法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“React中的任务调度算法是什么”吧!

React中的任务调度算法是什么

React中的任务池

React中的Fiber任务都应该知道吧,而且不同的Fiber任务有不同的优先级,React需要先处理优先级高的任务。例如,用户的点击和输入,这些都是高优先级的任务,因为用户的操作肯定希望马上就会有效果,这样才能提升用户体验。而比如animation事件的优先级肯定要低一点。新进来的高优先级任务进去队列后,React需要优先处理。

为了存储这些任务,React中有两个任务池。

// Tasks are stored on a min heap
var taskQueue = [];
var timerQueue = [];

taskQueue与timerQueue都是数组,前者存储的是立即要执行的任务,而后者存的则是可以延迟执行的任务。

  var newTask = {
    id: taskIdCounter++, // 标记任务id
    callback, // 回调函数
    priorityLevel, // 任务优先级
    startTime, // 任务开始时间,时间点
    expirationTime, // 过期时间,时间点
    sortIndex: -1, // 任务排序,取值来自过期时间,因此值越小,优先级越高
  };

React中一旦来了新任务,就会先用currentTime记录当前时间(perfORMance.now()或者Date.now()),如果任务有delay参数,那么任务开始执行时间startTime = currentTime + delay;。接下来通过startTime > currentTime如果成立,证明任务是可以延期的,那么任务进入timerQueue,否则进入taskQueue。

React中的任务调度

React怎么找到优先级最高的任务呢,以taskQueue为例,它是动态的任务池(任务队列),数据形式上就是一个数组。当然可以根据优先级进行排序,也就是Array.sort,当有新任务入队后,先排序,然后找出优先级最高的任务执行。但是Array.sort的平均时间复杂度是O(nlogn),并不是最好的解决方案。

taskQueue的newTask中排序用的是sortIndex,这个值取自过期时间expirationTime,也就意味着优先级越高的任务越需要理解执行,那么过期时间就越小,也就是说,优先级越高,过期时间就越小,sortIndex自然就越小。其实,这就是一种优先队列

React中的任务调度算法是什么

优先队列

优先队列也是一种队列(首先它是一个队列,其次是尾进头出),只不过不同的是,优先队列的出队顺序是按照优先级来的;在有些情况下,可能需要找到元素集合中的最小或者最大元素,可以利用优先队列ADT来完成操作,优先队列ADT是一种数据结构,它支持插入和删除最小值操作(返回并删除最小元素)或删除最大值操作(返回并删除最大元素)。

如果最小键值元素拥有最高的优先级,那么这种优先队列叫做,升序优先队列(即总是先删除最小的元素)。类似的,如果最大键值元素拥有最高的优先级,那么这种优先队列叫作降序优先队列(即总是先删除最大的元素);由于这两种类型时对称的,所以只需要关注其中一种,如升序优先队列。

例如:买车票的时候,我们都在排队,优先级是一样的,谁在队伍前面,谁就先买票,但是这时候来了个军人,他的优先级高,直接就排在了队伍的最前面。

在React中用最小堆(小根堆,小顶堆。。。)来实现这种功能。就是把taskQueue变成最小堆,然后取出对顶任务执行,对taskQueue堆化,维持它依然是一个最小堆的数据结构。往taskQueue插入新任务的时候,也要进行堆化,始终保持它是一个最小堆。

优先队列和堆的关系

有些地方称堆为优先队列(不准确),首先它是队列,有队列的特性,也就是“先进先出”。其次这个队列中的元素是有优先级的,优先级高的会排在前面。

准确来说,堆是实现优先队列的一种方式。当然优先队列还可以用其他方式来实现。

React中的任务调度算法是什么

React中的最小堆

之前我们说过堆排序是不稳定排序,但taskQueue希望这个过程是稳定的,也就是说,如果有可能两个任务的过期时间一样,那这个时候就要看谁先进入的任务池了,也就是newTask的id的值,每次来了新任务,id都会加1。

function compare(a, b) {
  // Compare sort index first, then task id.
  const diff = a.sortIndex - b.sortIndex;
  return diff !== 0 ? diff : a.id - b.id;
}

最小堆

在了解最小堆之前,先来温习一下基础知识。

二叉树

是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。

满二叉树

除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树

从图形形态上看,满二叉树外观上是一个三角形。

如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。

React中的任务调度算法是什么

满二叉树,是“女儿双全”,非常圆满,所以叫满二叉树。

完美二叉树

除去叶子节点, 所有节点的度都是 2。也就是说,所有的节点的度只能是0或2。

React中的任务调度算法是什么

完美二叉树,要么没有孩子,要么儿女双全。

满二叉树 VS 完美二叉树

满二叉树的英文原文:
A Full Binary Tree (FBT) is a tree in which every node other than the leaves has two children.

完美二叉树的英文原文:

A Perfect Binary Tree(PBT) is a tree with all leaf nodes at the same depth. All internal nodes have degree 2.

国外的所有书籍参考的是最早翻译的关于满二叉树,和完美二叉树的教材,但是最早翻译的文章翻译错了。现在国内的话,我们只能将错就错了(所有人都错,那错的也就是对的了。比如说客。。。)。如果要和外国友人讨论这两个概念,就要注意了哦。

完全二叉树

A Complete Binary Tree (CBT) is a binary tree in which every level,except possibly the last, is completely filled, and all nodes are as far left as possible.

一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

  • 除了最后一层外, 所有层都完美填充

  • 最后一层所有叶子节点靠左对齐

React中的任务调度算法是什么

React中的任务调度算法是什么

堆是一棵完全二叉树。

堆总是满足下列性质:

  • 堆总是一棵完全二叉树;

  • 堆中某个节点的值总是不大于或不小于其父节点的值;

还要先认识下大根堆和小根堆,完全二叉树中所有节点均大于(或小于)它的孩子节点,所以这里就分为两种情况,最大堆和最小堆。

最大堆

  • 如果所有节点**「大于」孩子节点值,那么这个堆叫做「最大堆」**,堆的最大值在根节点。

最小堆

  • 如果所有节点**「小于」孩子节点值,那么这个堆叫做「最小堆」**,堆的最小值在根节点。

React中的任务调度算法是什么

堆通常是一个可以被看做一棵 完全二叉树 的数组对象。 当然,二叉树也可以用数组表示。

React中的任务调度算法是什么

堆的实现

核心思想是,先建堆,后调整。

创建堆

对于二叉树(数组表示),我们从下往上进行调整,从**「第一个非叶子节点」**开始向前调整,对于调整的规则如下:

建堆是一个O(n)的时间复杂度过程。

①从第一个非叶子节点开始判断交换下移(shiftDown),使得当前节点和子孩子能够保持堆的性质

②但是普通节点替换可能没问题,对如果交换打破子孩子堆结构性质,那么就要重新下移(shiftDown)被交换的节点一直到停止。

React中的任务调度算法是什么

调整堆

堆构造完成,取第一个堆顶元素为最小(最大),剩下左右孩子依然满足堆的性值,但是缺个堆顶元素,如果给孩子调上来,可能会调动太多并且可能破坏堆结构。

① 所以索性把最后一个元素放到第一位。这样只需要判断交换下移(shiftDown),不过需要注意此时整个堆的大小已经发生了变化,我们在逻辑上不会使用被抛弃的位置,所以在设计函数的时候需要附带一个堆大小的参数。

② 重复以上操作,一直堆中所有元素都被取得停止。

React中的任务调度算法是什么

而堆算法复杂度的分析上,之前建堆时间复杂度是O(n)。而每次删除堆顶然后需要向下交换,每个个数为logn个。这样复杂度就为O(nlogn),总的时间复杂度为O(n)+O(nlogn)=O(nlogn)。

堆的应用场景

堆适合维护集合的最值。

堆pop出一个元素后,再次调整获取堆顶元素(也就是第二个最值)的花销比较低,因为pop出元素后,堆是一个半成品,在一个半成品上获取第二个最值的cost当然比较低,时间复杂度为O(logn),但如果遍历一遍找到第二个最值的话,时间复杂度为O(n)。

代码实现

代码采用javascript es6的写法。

代码

class Heap {
    constructor(data, comp) {
       this.data = data ? data : [];
 
       // 比较规则:更加灵活,可以比较数值,也可以比较对象
       this.compartor = comp ? comp : (a-b) => a-b;
 
       // 调整为堆(优先队列)
       this.heapify();
    }
 
    heapify() {
       if(this.size() <= 1) return;
       
       // 从第一个非叶子节点开始调整,也可以从最后一个元素开始调整
       for(let i=Math.floor((this.size()-2)/2); i>=0; i--) {
          // 调整堆, 向下调整也可以用递归来实现,这里用迭代来实现
          this.shiftDown(i);
       }
    }
 
    // 向下调整
    shiftDown(i) {
       let left = 2*i +1;
       let right = 2*i +2;
 
       let len = this.size();
       while(i < len) {
          let findIndex = i;
          // 左孩子更“大”
          if(left < len && this.compartor(this.data[left], this.data[findIndex]) < 0) {
             findIndex = left;
          }
          // 右孩子更“大”
          if(right < len && this.compartor(this.data[right], this.data[findIndex]) < 0) {
             findIndex = right;
          }
 
          if(i !== findIndex) {
              // 当前节点和更“大”的值进行交换
             [this.data[i], this.data[findIndex]] = [this.data[findIndex], this.data[i]];
 
             // 调整完本层,可能会影响下层的堆的特性,所以要继续调整下层(迭代实现,也可以递归)
             i = findIndex;
             left = 2*i +1;
             right = 2*i +2;
          }
          else {
              // 如果无需调整,则跳出(必须跳出,否则循环无法结束)
             break;
          }
       }
    }
 
    // 向上调整
    shiftUp(i){
       // 找到parent的下标
       let parentIndex = Math.floor((i-1)/2);
 
       // 最高调整到0
       while(parentIndex >=0 ) {
          let findIndex = i;
          if(this.compartor(this.data[parentIndex], this.data[findIndex]) > 0) {
             findIndex = parentIndex;
          }
 
          if(findIndex !== i) {
             [this.data[i], this.data[findIndex]] = [this.data[findIndex], this.data[i]];
             i = findIndex;
             parentIndex = Math.floor((i-1)/2);
          }
          else {
              break;
          }
       }
    }
 
    // 获取堆中所有元素的个数
    size(){
        return this.data.length;
    }
 
    // 获取堆首部元素
    peek(){
        if(!this.size()) return null;
 
        return this.data[0];
    }
 
    // 往堆中添加一个元素
    push(x){
       this.data.push(x);
       
       this.shiftUp(this.data.length-1);
    }
 
    // 从堆里弹出堆首元素
    pop(){
      if(!this.size()) return null;
 
      let res = this.data[0];
 
      if(this.size() == 1) {
         this.data.pop();
      }
      else {
          this.data[0] = this.data[this.data.length-1];
          this.data.length = this.data.length-1;
          this.shiftDown(0);
      }
 
      return res;
    }
 }

测试

 let arr = [2,9,8,6,3,10,5,7,4,1];
 let comp = (a, b) => a-b;
 let heap = new Heap(arr, comp);
 
 let res = [];
 while(heap.size()) {
    res.push(heap.pop());
 }

 console.log(res);

arr里的元素也可以是一个对象。

React源码部分

React源码中的目录packages/scheduler,就是React的任务调度模块相关的代码。

React中的任务调度算法是什么



type Heap = Array<Node>;
type Node = {|
  id: number,
  sortIndex: number,
|};

export function push(heap: Heap, node: Node): void {
  const index = heap.length;
  heap.push(node);
  siftUp(heap, node, index);
}

export function peek(heap: Heap): Node | null {
  const first = heap[0];
  return first === undefined ? null : first;
}

export function pop(heap: Heap): Node | null {
  const first = heap[0];
  if (first !== undefined) {
    const last = heap.pop();
    if (last !== first) {
      heap[0] = last;
      siftDown(heap, last, 0);
    }
    return first;
  } else {
    return null;
  }
}

function siftUp(heap, node, i) {
  let index = i;
  while (true) {
    const parentIndex = (index - 1) >>> 1;
    const parent = heap[parentIndex];
    if (parent !== undefined && compare(parent, node) > 0) {
      // The parent is larger. Swap positions.
      heap[parentIndex] = node;
      heap[index] = parent;
      index = parentIndex;
    } else {
      // The parent is smaller. Exit.
      return;
    }
  }
}

function siftDown(heap, node, i) {
  let index = i;
  const length = heap.length;
  while (index < length) {
    const leftIndex = (index + 1) * 2 - 1;
    const left = heap[leftIndex];
    const rightIndex = leftIndex + 1;
    const right = heap[rightIndex];

    // If the left or right node is smaller, swap with the smaller of those.
    if (left !== undefined && compare(left, node) < 0) {
      if (right !== undefined && compare(right, left) < 0) {
        heap[index] = right;
        heap[rightIndex] = node;
        index = rightIndex;
      } else {
        heap[index] = left;
        heap[leftIndex] = node;
        index = leftIndex;
      }
    } else if (right !== undefined && compare(right, node) < 0) {
      heap[index] = right;
      heap[rightIndex] = node;
      index = rightIndex;
    } else {
      // Neither child is smaller. Exit.
      return;
    }
  }
}

function compare(a, b) {
  // Compare sort index first, then task id.
  const diff = a.sortIndex - b.sortIndex;
  return diff !== 0 ? diff : a.id - b.id;
}

我们自己实现的最小堆和React中的实现略有不同,但是思路是一样的,只是代码写法不同而已。

感谢各位的阅读,以上就是“React中的任务调度算法是什么”的内容了,经过本文的学习后,相信大家对React中的任务调度算法是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: React中的任务调度算法是什么

本文链接: https://www.lsjlt.com/news/98303.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • React中的任务调度算法是什么
    这篇文章主要讲解了“React中的任务调度算法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“React中的任务调度算法是什么”吧!React中的任务池...
    99+
    2022-10-19
  • 编程语言中任务调度的并行算法是什么
    编程语言中任务调度的并行算法是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。如果给定一批任务,比如有500个任务,需要在尽可能快的时间内做完。如果串行是肯定不行的。我们...
    99+
    2023-06-02
  • 云服务器调度算法是什么
    云服务器调度算法的主要组成部分包括: 调度器:调度器是云服务器的核心部分,它负责对云服务器的请求进行分发和处理。调度器通常是一个计算机程序,它负责根据请求的内容和云服务器的性能来决定如何分发请求。调度器还要负责对请求进行监控和管理,以便...
    99+
    2023-10-27
    算法 服务器
  • React调度的原理是什么
    这篇文章主要介绍“React调度的原理是什么”,在日常操作中,相信很多人在React调度的原理是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”React调度的原理是什么”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-07-02
  • Python怎么实现任务调度并行算法
    本篇内容介绍了“Python怎么实现任务调度并行算法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!本来自己想先使用Java来写一个版本,然后...
    99+
    2023-06-04
  • linux任务调度机制指的是什么
    本篇内容主要讲解“linux任务调度机制指的是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“linux任务调度机制指的是什么”吧!linux的任务调度机制是指系统在某个事件执行的特定命令或程...
    99+
    2023-07-02
  • SpringBoot Schedule调度任务的动态管理方法是什么
    这篇文章主要介绍了SpringBoot Schedule调度任务的动态管理方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot Schedule调度任务的动态管理方法...
    99+
    2023-07-05
  • React中diff算法是什么
    这篇文章主要介绍了React中diff算法是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。React中diff算法的理解diff算法用来计算出Virtual DOM中改变...
    99+
    2023-06-15
  • java线程调度算法是什么
    Java线程调度算法是由Java虚拟机(JVM)负责的。JVM使用了一种抢占式调度算法,即根据线程的优先级来决定该调度哪个线程执行。...
    99+
    2023-08-30
    java
  • Python的周期任务调度工具是什么
    本篇内容主要讲解“Python的周期任务调度工具是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python的周期任务调度工具是什么”吧!如果你想周期性地执行某个 Python 脚本,最出名...
    99+
    2023-06-15
  • Java进程调度算法指的是什么
    这篇文章主要介绍了Java进程调度算法指的是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java进程调度算法指的是什么文章都会有所收获,下面我们一起来看看吧。该工程主要有三个实现类:Process(进程类...
    99+
    2023-06-26
  • React的调度机制原理是什么
    这篇文章主要介绍“React的调度机制原理是什么”,在日常操作中,相信很多人在React的调度机制原理是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”React的调度机制...
    99+
    2022-10-19
  • 负载均衡调度算法是什么
    负载均衡调度算法是一种用于分配请求到多个服务器的算法,以实现在不同服务器之间平衡负载的目的。负载均衡调度算法根据不同的策略和条件来选...
    99+
    2023-09-02
    负载均衡
  • Java进程调度算法的概念是什么
    这篇“Java进程调度算法的概念是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java进程调度算法的概念是什么”文章吧...
    99+
    2023-07-02
  • Kubernetes调度算法是怎么使用的
    Kubernetes调度算法是怎么使用的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。调度流程调度器就是一个独立的进程,负责不断从apiserver拉取还没有被调度的pod...
    99+
    2023-06-19
  • React中的任务饥饿行为是什么意思
    本篇内容主要讲解“React中的任务饥饿行为是什么意思”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“React中的任务饥饿行为是什么意思”吧!本文是在React...
    99+
    2022-10-19
  • C#中抢占式优先级调度算法是什么意思
    本篇内容主要讲解“C#中抢占式优先级调度算法是什么意思”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#中抢占式优先级调度算法是什么意思”吧!系统把处理机分配给优先权最高的进程,使之执行。但在其...
    99+
    2023-06-20
  • 在Go语言中如何解决并发任务的调度算法优化问题?
    在Go语言中如何解决并发任务的调度算法优化问题?Go语言作为一门旨在解决并发编程问题的语言,提供了丰富的并发特性和机制。然而,在实际应用中,我们常常遇到需要优化并发任务调度的问题。本文将介绍一种优化并发任务调度算法的方法,并给出具体的代码示...
    99+
    2023-10-22
    并发任务调度 Go语言并发优化 调度算法优化
  • golang调度器的用法是什么
    Golang调度器是Go编程语言中的一种机制,用于协调并发执行的goroutine。调度器负责在可用的处理器上调度goroutine...
    99+
    2023-10-20
    golang
  • docker在深度学习任务中的应用是什么
    本篇内容主要讲解“docker在深度学习任务中的应用是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“docker在深度学习任务中的应用是什么”吧!1 软件安装之痛Docker是一种容器技术,...
    99+
    2023-06-19
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作