HTML5 Web Worker之性能优化

描述

由于 JavaScript 是单线程的,当执行比较耗时的任务时,就会阻塞主线程并导致页面无法响应,这就是 Web Workers 发挥作用的地方。它允许在一个单独的线程(称为工作线程)中执行耗时的任务。这使得 JavaScript 代码可以在后台执行,而不会阻塞主线程并导致页面无响应。

Web Worker 是一个作为后台线程运行的脚本,具有自己的引擎实例和事件循环。它与主执行线程并行运行,并且不会阻塞事件循环。

主线程(或工作线程本身)可以启动任意数量的工作线程。生成 worker 脚本:

  1. 主线程(或另一个工作线程)向新工作线程发送一条消息,其中包含所有必要的数据。

  2. 工作线程中的事件处理程序执行并开始处理数据。

  3. 完成(或失败)时,工作线程将一条带有计算结果的消息发送回主线程。

  4. 主线程中的事件处理程序执行、解析传入结果并运行必要的操作(例如显示值)。

重要性

Web Workers 为开发人员提供了在 Web 上实现多线程的方式,这对于构建高性能的 Web 应用至关重要。通过将耗时的任务在后台独立于主线程中执行,Web Workers 提高了网页的整体响应性,并使用户体验更加流畅。以下是 Web Workers 在 Web 多线程中的重要性和好处:

通过资源利用率

通过允许耗时任务在后台执行,Web Workers 更有效地利用系统资源,实现更快速和高效的数据处理,并提高整体性能。这对于涉及大量数据处理或图像操作的 Web 应用尤为重要,因为 Web Workers 可以在不影响用户界面的情况下执行这些任务。

增加稳定性和可靠性

通过将耗时任务隔离到单独的 worker 线程中,Web Workers 帮助防止在主线程上执行大量代码时发生崩溃和错误。这使得开发人员更容易编写稳定可靠的 Web 应用,减少用户的烦恼和数据丢失的可能性。

增强安全性

Web Workers 在与主线程分离的隔离环境中运行,这有助于提高 Web 应用的安全性。此隔离防止恶意代码访问或修改主线程或其他 Web Workers 中的数据,降低数据泄露或其他安全漏洞的风险。

更好的资源利用率

Web Workers 可以通过将耗时计算放到后台,使主线程用于处理用户输入和其他任务来帮助提高资源利用率。这有助于提高系统的整体性能并减少崩溃或错误的可能性。此外,通过利用多个 CPU 核心,Web Workers 可以更有效地利用系统资源,实现更快速和高效的数据处理。

Web Workers 还能够实现更好的负载平衡和扩展应用。通过允许任务在多个 worker 线程之间并行执行,Web Workers 可以帮助将工作负荷均匀分配到多个核心或处理器上,实现更快速和高效的数据处理。这对于经历高流量或需求的应用尤为重要,因为 Web Workers 可以帮助确保应用可以处理增加的负载而不影响性能。

Web Workers 客户端使用

使用 JavaScript 创建 Web Worker 的步骤如下:

  1. 创建一个新的 JavaScript 文件,其中包含要在工作线程中运行的代码(耗时任务)。该文件不应包含对 DOM 的引用,因为在工作线程中无法访问 DOM。

  2. 在主 JavaScript 文件中,使用 Worker 构造函数创建一个新的worker对象。此构造函数接收一个参数,即在步骤 1 中创建的 JavaScript 文件的 URL。

const worker = new Worker('worker.js');
  1. worker对象添加事件侦听器以处理主线程和工作线程之间发送的消息。onmessage 用于处理从工作线程发送来的消息,postMessage 用于向工作线程发送消息。

worker.onmessage = function(event) {
  console.log('Worker: ' + event.data);
};

worker.postMessage('Hello, worker!');
  1. 在 Web Worker 的 JavaScript 文件中,使用self对象的onmessage属性添加一个事件监听器来处理从主线程发出的消息。可以使用event.data属性访问发送的消息数据。

self.onmessage = function(event) {
  console.log('Main: ' + event.data);
  self.postMessage('Hello, Main!');
};

接下来就运行应用并测试 Worker。可以在控制台看到以下信息,表示主线程和 Worker 线程之间发送和接收了消息。

Main:Hello worker!
Worker:Hello Main!

我们可以使用terminate()函数来终止一个工作线程,或者通过调用self上的close()函数使其自行终止。

// 从应用中终止一个工作线程
worker.terminate();
// 让一个工作线程自行终止
self.close();

可以使用importScripts()函数将库或文件导入到工作线程中,该函数可以接受多个文件。以下示例将script1.jsscript2.js加载到工作线程 worker.js 中:

importScripts('script1.js','script2');

可以使用 onerror函数来处理工作线程抛出的错误:

worker.onerror = function(err) {
    console.log("遇到错误")
}

Web Workers 服务端应用

服务器端 JavaScript 运行时也支持 Web Worker:

  • Node.js 在版本 10 中实现了类似 Web Worker 的功能,称为 Worker thread(工作进程)。

  • Deno 复制了 Web Worker API,因此语法与浏览器代码完全相同。它还提供了兼容模式,可以填充 Node.js API,以便可以使用该运行时的工作线程语法。

  • Bun 将支持浏览器和 Node.js 的 Web Worker API。

基本使用

要在 Node.js 中使用 Web Worker,主脚本必须定义一个 Worker 对象,其中包含相对于项目根目录的 Web Worker 脚本的名称。第二个参数定义了一个对象,其中包含一个workerData属性,该属性包含要发送的数据:

const worker = new Worker('./worker.js', {
  workerData: { a: 1, b: 2, c: 3 }
});

与浏览器中的 Web Worker 不同, 它在启动时无需运行worker.postMessage()。如果需要的话,可以调用该方法并稍后发送更多数据,它会触发parentPort.on('message')事件处理程序:

parentPort.on('message', e => {
  console.log(e);
});

一旦工作线程完成处理,它会使用以下方法将结果数据发送回主线程:

parentPort.postMessage(result);

这将在在主脚本中触发 message 事件,主线程接收到 worker 返回的结果:

worker.on('message', result => {
  console.log( result );
});

在发送完消息后,worker 就会终止。这也会触发一个exit事件,如果希望运行清理或其他函数,可以利用这个事件:

worker.on('exit', code => {
//...
});

除此之外,还支持其他事件处理:

  • messageerror:当 worker 收到无法反序列化的数据时触发。

  • online:当 worker 开始执行时触发。

  • error:当 worker 脚本中发生 JavaScript 错误时触发。

在服务端,一个单独的 Node.js 脚本文件可以同时包含主线程和工作线程的代码。脚本必须使用isMainThread检查自身是否在主线程上运行,然后将自身作为工作线程进行调用(可以在 ES 模块中使用import.meta.url作为文件引用,或者在 CommonJS 中使用__filename)。

import { Worker, isMainThread, workerData, parentPort } from "node:worker_threads";

if (isMainThread) {
  // 主线程
  const worker = new Worker(import.meta.url, {
    workerData: { a: 1, b: 2, c: 3 }
  });

  worker.on('message', msg => {});
  worker.on('exit', code => {});
}
else {
  // 工作线程
  const result = runSomeProcess( workerData );
  parentPort.postMessage(result);
}

这种方式更快,并且对于小型、自包含的单脚本项目来说是一个选择。如果是大型项目,将 worker 脚本文件分开会更容易维护。

数据通信

主线程和工作线程之间的通信涉及到了数据序列化。可以使用表示固定长度原始二进制数据的SharedArrayBuffer对象在线程之间共享数据。以下是一个示例,主线程定义了从 0 到 99 的 100 个数字元素,并将其发送给工作线程:

// main.js
import { Worker } from "node:worker_threads";

const
  buffer = new SharedArrayBuffer(100 * Int32Array.BYTES_PER_ELEMENT),
  value = new Int32Array(buffer);

value.forEach((v,i) => value[i] = i);

const worker = new Worker('./worker.js');

worker.postMessage({ value });

工作线程可以接收 value对象:

// worker.js
import { parentPort } from 'node:worker_threads';

parentPort.on('message', value => {
  value[0] = 100;
});

主线程或工作线程都可以更改值数组中的元素,数据将在两个线程之间保持一致。这可能会提高性能,但有一些缺点:

  • 只能共享整数数据。

  • 可能仍需要通知另一个线程更改。

  • 存在两个线程可能同时更新同一值并且失去同步的风险。

Node.js 子进程

在 Node.js 中,除了使用工作线程外,还可以使用子进程来实现类似的功能。子进程用于启动其他应用、传递数据并接收结果。它们与工作线程类似,但通常效率较低,进程开销较大。

子进程和工作线程的选择取决于具体的应用场景。如果只需要在 Node.js 中执行其他任务或命令,子进程是一种更好的选择。但如果需要在 Node.js 中进行复杂的计算或处理任务,Web Worker 可能更适合。

Web Workers 应用场景

Web Workers 在实际应用中有许多常见且有用的应用场景。

处理 CPU 密集任务

假设有一个应用需要执行大量的 CPU 密集型计算。如果在主线程中执行这些计算,用户界面可能会变得无响应,用户体验将受到影响。为了避免这种情况,可以使用 Web Worker 在后台执行这些计算。

在主线程中:

// 创建一个新的 Web Worker
const worker = new Worker('worker.js');

// 定义一个函数来处理来自Web Worker的消息
worker.onmessage = function(event) {
  const result = event.data;
  console.log(result);
};

// 向Web Worker发送一个消息,以启动计算
worker.postMessage({ num: 1000000 });

在 worker.js 中:

// 定义一个函数来执行计算
function compute(num) {
  let sum = 0;
  for (let i = 0; i < num; i++) {
    sum += i;
  }
  return sum;
}

// 定义一个函数来处理来自主线程的消息
onmessage = function(event) {
  const num = event.data.num;
  const result = compute(num);
  postMessage(result);
};

在这个例子中,创建了一个新的 Web Worker,并定义了一个函数来处理来自 Web Worker 的消息。然后,向 Web Worker 发送一条消息,并提供一个参数(num),指定要执行计算的迭代次数。Web Worker 接收到这条消息后,在后台执行计算。当计算完成后,Web Worker 向主线程发送一条包含结果的消息。主线程收到这个消息后,将结果记录到控制台中。

图片

在上面的例子中,向 Web Worker 的compute()函数传递了数字 1000000。这意味着compute函数将需要将从 0 到一百万的所有数字相加。这涉及大量的额外操作,可能需要很长时间才能完成,特别是如果代码在较慢的计算机上运行或在浏览器标签中同时处理其他任务。

通过将这个任务分配给 Web Worker,应用的主线程可以继续平稳运行,而不会被计算密集型的任务阻塞。这使得用户界面保持响应,并确保其他任务(如用户输入或动画)可以在没有延迟的情况下处理。

处理网络请求

假设有一个应用需要发起大量的网络请求。如果在主线程中执行这些请求,可能会导致用户界面无响应,用户体验差。为了避免这个问题,可以利用 Web Worker 在后台处理这些请求。通过这样做,主线程可以同时执行其他任务,而 Web Worker 负责处理网络请求,从而提高性能和改善用户体验。

在主线程中:

// 创建一个新的 Web Worker
const worker = new Worker('worker.js');

// 定义一个函数来处理来自Web Worker的消息
worker.onmessage = function(event) {
  const response = event.data;
  console.log(response);
};

// 向Web Worker发送一个消息,以启动计算
worker.postMessage({ urls: ['https://api.example.com/foo', 'https://api.example.com/bar'] });

在 worker.js 中:

// 定义一个函数来执行网络请求
function request(url) {
  return fetch(url).then(response => response.json());
}

// 定义一个函数来处理来自主线程的消息
onmessage = async function(event) {
  const urls = event.data.urls;
  const results = await Promise.all(urls.map(request));
  postMessage(results);
};

在这个例子中,创建一个新的 Web Worker 并定义一个函数来处理来自该 Worker 的消息。然后,向 Worker 发送一个包含一组 URL 请求的消息。Worker 接收到这个消息后,在后台使用 fetch API 执行请求。当所有请求完成后,Worker 向主线程发送包含结果的消息。主线程接收到这个消息后,将结果记录到控制台中。

并行处理

假设应用需要执行大量独立计算。 如果在主线程中依次执行这些计算,用户界面将变得无响应,用户体验将受到影响。 为了避免这种情况,可以实例化多个 Web Worker 来并行执行计算。

在主线程中:

// 创建三个新的 Web Worker
const worker1 = new Worker('worker.js');
const worker2 = new Worker('worker.js');
const worker3 = new Worker('worker.js');


// 定义三个处理来自 worker 的消息的函数
worker1.onmessage = handleWorkerMessage;
worker2.onmessage = handleWorkerMessage;
worker3.onmessage = handleWorkerMessage;

function handleWorkerMessage(event) {
  const result = event.data;
  console.log(result);
}

// 将任务分配给不同的 worker 对象,并发送消息启动计算
worker1.postMessage({ num: 1000000 });
worker2.postMessage({ num: 2000000 });
worker3.postMessage({ num: 3000000 });

在 worker.js 中:

// 定义一个函数来执行单个计算
function compute(num) {
  let sum = 0;
  for (let i = 0; i < num; i++) {
    sum += i;
}
  return sum;
}

// 定义一个函数来处理来自主线程的消息
onmessage = function(event) {
  const result = compute(event.data.num);
  postMessage(result);
};

在这个例子中,创建三个新的 Web Worker 并定义一个函数来处理来自该 Worker 的消息。然后,向三个 Worker 分别发送一个要计算的数字消息。Worker 接收到这个消息后执行计算。当计算完成后,Worker 向主线程发送包含结果的消息。主线程接收到这个消息后,将结果记录到控制台中。

Web Workers 使用限制

Web Worker 是一个提高 Web 应用性能和响应能力的强大工具,但它们也有一些限制和注意事项。

浏览器支持

目前所有主流浏览器、Node.js、Deno 和 Bun 都支持 Web Workers。

图片

 

对 DOM 的访问受到限制

Web Worker 在单独的线程中运行,无法直接访问主线程中的 DOM 或其他全局对象。这意味着不能直接从 Web Worker 中操作 DOM,也不能访问像windowdocument这样的全局对象。

为了解决这个限制,可以使用postMessage方法与主线程进行通信,间接地更新 DOM 或访问全局对象。例如,使用postMessage将数据发送到主线程,然后根据接收到的消息来更新 DOM 或全局对象。

另外,还有一些库可以帮助解决这个问题。例如,WorkerDOM[1] 库允许在 Web Worker 中运行 DOM,从而加快页面的渲染速度并提高性能。

现代桌面浏览器支持共享工作线程,即在不同窗口、iframes 或工作线程中可被多个脚本访问的单个脚本,它们通过独立的端口进行通信。但是,大多数移动浏览器不支持共享工作线程,所以对于大多数 Web 项目来说,它们并不实用。

通信开销大

Web Worker 使用postMessage方法与主线程进行通信,这可能会引入通信开销。通信开销指的是在两个或多个计算系统之间建立和维护通信所需的时间和资源量,比如在 Web 应用中,Web Worker 与主线程之间的通信。这可能导致消息处理延迟,潜在地减慢应用程序的速度。为了最小化这种开销,应该只在线程之间发送必要的数据,避免发送大量数据或频繁发送消息。

调试工具有限

与在主线程中调试代码相比,调试 Web Worker 可能更具挑战性,因为可用的调试工具较少。为了简化调试过程,可以使用控制台 API 在 Worker 线程中记录消息,并使用浏览器开发者工具检查线程之间发送的消息。

代码复杂度

使用 Web Worker 可能会增加代码的复杂性,因为需要管理线程之间的通信,并确保数据正确传递。这可能会使编写、调试和维护代码更加困难,因此应该仔细考虑是否有必要在应用中使用 Web Worker。

Web Workers 实践

上面提到了在使用 Web Workers 时,可能会出现的一些潜在问题。下面就来看看如何缓解这些问题。

worker.on('message', result => {
  console.log( result );
});

消息批处理

消息批处理涉及将多个消息组合成一个批处理消息,这比单独发送个别消息更有效。这种方法减少了主线程和 Web Worker 之间往返的数量,它有助于最小化通信开销并提高应用的整体性能。

为了实现消息批量处理,可以使用队列来累积消息,并在队列达到一定阈值或经过设定时间后将消息批量发送。下面来在 Web Worker 中简单实现消息的批处理:

// 创建一个消息队列累积消息
const messageQueue = [];

// 创建一个将消息添加到队列的函数
function addToQueue(message) {
  messageQueue.push(message);

  // 检查队列是否达到阈值大小
  if (messageQueue.length >= 10) {
    // 如果是,请将批处理消息发送到主线程
    postMessage(messageQueue);

    // 清除消息队列
    messageQueue.length = 0;
  }
}

// 将消息添加到队列中
addToQueue({type: 'log', message: 'Hello, world!'});

// 再添加另一条消息到队列中
addToQueue({type: 'error', message: 'An error occurred.'});

在这个例子中, 创建了一个消息队列,用于累积需要发送到主线程的消息。每当使用addToQueue函数将消息添加到队列时,检查队列是否已达到阈值大小(10)。如果是,则使用postMessage方法将批处理消息发送到主线程。然后,清除消息队列,以准备进行下一次批处理。

通过以这种方式批处理消息,可以减少主线程和 Web Worker 之间发送的消息总数,从而提高应用性能。

避免同步方法

同步方法是阻塞其他代码执行的 JavaScript 函数或操作。同步方法可以阻塞主线程,导致应变得无响应。为了避免这种情况,应尽量避免在 Web Worker 中使用同步方法。而应该使用setTimeout()setInterval()等异步方法来执行长时间运行的计算。

// 在Web Worker中
self.addEventListener('message', (event) => {
  if (event.data.action === 'start') {
    // 使用setTimeout来异步执行计算
    setTimeout(() => {
      const result = doSomeComputation(event.data.data);

      // 将结果发送回主线程
      self.postMessage({ action: 'result', data: result });
    }, 0);
  }
});

注意内存使用情况

Web Workers 有自己的内存空间,这个空间根据用户的设备和浏览器设置可能是有限的。为了避免内存问题,应该注意你的 Web Worker 代码使用的内存量,并避免不必要地创建大对象。例如:

// 在Web Worker中
self.addEventListener('message', (event) => {
  if (event.data.action === 'start') {
    // 使用for循环处理一个数据数组
    const data = event.data.data;
    const result = [];

    for (let i = 0; i < data.length; i++) {
      // 处理数组中的每个项,并将结果添加到结果数组中
      const itemResult = processItem(data[i]);
      result.push(itemResult);
    }

    // 将结果发送回主线程
    self.postMessage({ action: 'result', data: result });
  }
});

在这段代码中,Web Worker 处理一个数据数组,并使用postMessage方法将结果发送回主线程。然而,用于处理数据的 for 循环可能耗时较长。

导致这个问题的原因是代码一次性处理了整个数据数组,这意味着所有的数据都必须同时加载到内存中。如果数据集非常大,这可能导致 Web Worker 消耗大量的内存,甚至超过浏览器为 Web Worker 分配的内存限制。

为了缓解这个问题,可以考虑使用内置的 JavaScript 方法,如forEachreduce,它们可以逐项处理数据,避免一次性加载整个数组到内存中。

浏览器兼容性

大多数现代浏览器都支持 Web Worker,但某些较旧的浏览器可能不支持它们。 为了确保与各种浏览器的兼容性,应该在不同的浏览器和版本中测试 Web Worker 代码。 还可以使用功能检测来检查 Web Worker 是否受支持,然后再在代码中使用它们,如下所示:

if (typeof Worker !== 'undefined') {
  const worker = new Worker('worker.js');
} else {
  console.log('Web Workers are not supported in this browser.');
}

这段代码会检查当前浏览器是否支持 Web Workers,并在支持时创建一个新的 Web Worker。如果 Web Workers 不受支持,则该代码记录一条消息到控制台,表示该浏览器不支持 Web Workers。

总结

Web Workers 是现代 Web 开发的一个基本特性,它允许开发人员将 CPU 密集型任务放到单独的线程中执行,从而提高应用的性能和响应能力。然而,在处理 Web Workers 时需要记住一些重要的限制和注意事项,例如无法访问 DOM 和数据类型之间传递的限制等。为了避免这些潜在问题,可以采用上面提到的策略,如使用异步方法并注意卸载的任务的复杂性。在未来,使用 Web Workers 进行多线程似乎仍然是提高 Web 应用程序性能和响应能力的重要技术。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Node.js:构建高性能网络应用的利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

吴恩达机器学习-可选实验室:逻辑回归,决策边界(Logistic Regression,Decision Boundary))

文章目录 目标数据集图数据逻辑回归模型复习逻辑回归和决策边界绘图决策边界恭喜 目标 在本实验中&#xff0c;你将:绘制逻辑回归模型的决策边界。这会让你更好地理解模型的预测。 import numpy as np %matplotlib widget import matplotlib.pyplot as plt from lab_utils_co…

基于WEB的服务器运行状态的监控分析系统

摘要: 随着云计算和电子商务规模的扩大和复杂性的增加&#xff0c;企业数据中心Web服务器数量急剧增加&#xff0c;用户对网络性能的要求也越来越高&#xff0c;导致企业和用户对数据中心的通信服务稳定性和快速响应要求越来越高。本作品提供一套行之有效的Web服务器性能监控系…

RabbitMQ - 05 - Direct交换机

部署demo项目 通过消息队列demo项目进行练习 相关配置看此贴 http://t.csdnimg.cn/hPk2T 注意 生产者消费者的yml文件也要配置好 什么是Direct交换机 Direct 交换机是 AMQP&#xff08;高级消息队列协议&#xff09;中的一种交换机类型&#xff0c;它根据消息的路由键&am…

【R语言】R包-探索ggtree进化树美化

文章目录 R包-探索ggtree进化树美化分析流程1. 关于包的下载2. 绘制一个基本的进化树图3. 添加样本名称3. 添加节点节点高亮4. 添加分组小结 R包-探索ggtree进化树美化 提示&#xff1a;基于nwk文件进行进化树美化&#xff0c;如更换进化树格式&#xff0c;添加分组、节点、遗传…

【大厂AI课学习笔记NO.78】智能芯片产业人才能力图谱

有志于从事智能芯片产业的朋友&#xff0c;可以参考下上面的图谱。 比如C站的程序猿很多&#xff0c;那么技能能力中&#xff0c;你要掌握的就包括C/C、Python、Bash等常用的编程语言。 还要熟悉TensorFlow、PyTorch等主流的深度学习框架。 这两个框架&#xff0c;我们都介绍…

SpringSecurity两种验证方式及调用流程

一、HttpBasic方式 <security:http-basic/> 二、Formlogin方式 <security:form-login login-page"/userLogin" /> 三、SpringSecurity执行流程

论文阅读《FENET: FOCUSING ENHANCED NETWORK FOR LANE DETECTION》

ABSTRACT 受人类驾驶专注力的启发&#xff0c;这项研究开创性地利用聚焦采样&#xff08;Focusing Sampling&#xff09;、部分视野评估&#xff08;Partial Field of View Evaluation&#xff09;、增强型 FPN 架构和定向 IoU 损失&#xff08;Directional IoU Loss&#xff…

uniapp:小程序数字键盘功能样式实现

代码如下&#xff1a; <template><view><view><view class"money-input"><view class"input-container" click"toggleBox"><view class"input-wrapper"><view class"input-iconone"…

01hadoop概念

大数据与Hadoop 大数据指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 Hadoop是什么&#xff1f; Hadoop是一种分析和处理海量数据的…

OD_2024_C卷_200分_8、攀登者2【JAVA】【逻辑分析】

package odjava;import java.util.Arrays; import java.util.HashSet; import java.util.Scanner;public class 八_攀登者2 {// 输入处理public static void main(String[] args) {Scanner sc new Scanner(System.in);int[] heights Arrays.stream(sc.nextLine().split("…

驱动开发常见的通信接口介绍

本文将为您详细讲解驱动开发中常见的通信接口&#xff0c;以及它们的特点、区别和应用场景。在操作系统和硬件设备之间&#xff0c;通信接口扮演着至关重要的角色&#xff0c;它们定义了数据如何在软件和硬件之间传输和交互。 1. 串行通信接口&#xff08;Serial Communication…

防御保护作业六

实验拓扑图&#xff1a; 配置过程&#xff1a; FW1 自定义服务ike 创建nat策略&#xff0c;让10.0.2.0/24访问192.168.1.0/24的流量不进行nat转换,并将这条策略置于nat策略最上面&#xff0c;优先匹配 FW3 测试

CodeReview 规范及实施

优质博文&#xff1a;IT-BLOG-CN 一、为什么需要CodeReview 随着业务压力增大&#xff0c;引发代码质量下降&#xff0c;代码质量的下降导致了开发效率的降低&#xff0c;维护成功高等问题&#xff0c;开发效率下降后又加重了业务压力&#xff0c;最终陷入了死亡三角的内耗之…

Shell常用脚本:文件或目录一键同步到多台服务器

注意&#xff1a; 将本地文件&#xff0c;同步到【/opt/module/script/xsyncByFileIp.txt】里面的目标机器 xsyncByFile.sh #!/bin/bash# 入参参数个数 argsCount$#if(($argsCount0)); thenecho "同步失败&#xff1a;请输入待同步的文件或者目录" exit; fiecho &q…

【大厂AI课学习笔记NO.68】开源和开源发展情况

开源即源代码公开&#xff0c;任何人能获取源代码&#xff0c;查看、修改、分发他们认为合适的代码。 依托同行评审和社区生成&#xff0c;旨在以分散、协作的方式开发。 我们曾经很详细的讨论过开源协议的问题&#xff0c;详细可以参考我的文章&#xff1a; https://giszz.…

OpenCV的常用数据类型

OpenCV涉及的常用数据类型除包含C的基本数据类型,如&#xff1a;char、uchar&#xff0c;int、unsigned int,short 、long、float、double等数据类型外, 还包含Vec&#xff0c;Point、Scalar、Size、Rect、RotatedRect、Mat等类。C中的基本数据类型不需再做说明下面重点介绍一下…

flink重温笔记(十四): flink 高级特性和新特性(3)——数据类型及 Avro 序列化

Flink学习笔记 前言&#xff1a;今天是学习 flink 的第 14 天啦&#xff01;学习了 flink 高级特性和新特性之数据类型及 avro 序列化&#xff0c;主要是解决大数据领域数据规范化写入和规范化读取的问题&#xff0c;avro 数据结构可以节约存储空间&#xff0c;本文中结合企业真…

iOS17.4获取UDID安装mobileconfig描述文件失败 提示“安全延迟进行中”问题 | 失窃设备保护

iOS17.4这两天已经正式发布&#xff0c; 在iOS 17.4版本中新增了一个名为"失窃设备保护"的功能&#xff0c;并提供了一个"需要安全延迟"的选项。 iOS17.4获取UDID安装mobileconfig描述文件失败 提示“安全延迟进行中”问题 | 失窃设备保护 当用户选择启用…

贝叶斯优化的门控循环神经网络BO-GRU(时序预测)的Matlab实现

贝叶斯优化的门控循环神经网络&#xff08;BO-GRU&#xff09;是一种结合了贝叶斯优化&#xff08;Bayesian Optimization, BO&#xff09;和门控循环单元&#xff08;Gated Recurrent Unit, GRU&#xff09;的模型&#xff0c;旨在进行时序预测。这种模型特别适用于时间序列数…