Web Worker 用法

2023-10-31

一、概述

JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力。

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。

Web Worker 中的 “Worker” 是指执行代码的并行线程。

Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。

Web Worker 有以下几个使用注意点:

(1)同源限制

Worker 线程运行的脚本文件,必须和包含主线程脚本文件的文档同源。

(2)DOM 限制

Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用documentwindowparent这些对象,这就意味着,并行地修改DOM是不可能的。但是,Worker 线程可以读取navigator对象和location对象。

(3)通信联系

Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过异步消息传递机制来实现。

(4)脚本限制

Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。

(5)文件限制

Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自服务器。本地调试可以用 VSCode 的 Live Server 插件创建本地服务器。

二、基本用法

2.1 主线程

主线程采用new命令,调用Worker()构造函数,新建一个 Worker 线程。

var worker = new Worker('http://localhost:8088/pages/work.js');

Worker()构造函数的参数是一个脚本文件的url,该文件就是 Worker 线程所要执行的任务。如果url采用的是相对路径,那么是以包含调用 Worker() 构造函数脚本的文档的URL为参照的。而如果指定的URL采用的是绝对路径,那么必须和包含该脚本的文档是同源的。

由于 Worker 不能读取本地文件,所以这个脚本必须来自网络。如果下载没有成功(比如404错误),Worker 就会默默地失败。

然后,主线程调用worker.postMessage()方法,向 Worker 发消息,传递给 postMessage() 方法的值会结构性复制。提醒一下,Worker 的 postMessage() 方法和 Window 的 postMessage() 方法是两个不同的东西。

worker.postMessage('Hello World');
worker.postMessage({method: 'echo', args: ['Work']});

worker.postMessage()方法的参数,就是主线程传给 Worker 的数据。它可以是各种数据类型,包括二进制数据。

接着,主线程通过worker.onmessage指定监听函数,接收 Worker线程发回来的消息。

worker.onmessage = function (event) {
  console.log('Received message ' + event.data);
  doSomething();
}

function doSomething() {
  // 执行任务
  worker.postMessage('Work done!');
}

上面代码中,事件对象的data属性可以获取 Worker 发来的数据。

如果 Worker 抛出了异常,并且它自己没有对其进行捕获和处理,可以作为监听的一个error事件来传递该异常。

worker.onerror = function (e) { 
  // 记录错误消息日志:包括Worker的文件名和行数
  console.log('Error at ' + e.filename + ': ' + e.lineno + ': ' + e.message);
}

Worker 完成任务以后,主线程就可以把Worker线程关掉。

worker.terminate();

2.2 Worker 线程

Worker 线程运行在一个全新的js运行环境中,完全和创建Worker的脚本隔离。WorkerGlobalScope 全局对象表示了该新的运行环境。

Worker 线程内部需要有一个监听函数,监听message事件。

self.addEventListener('message', function (e) {
  self.postMessage('You said: ' + e.data);
}, false);

上面代码中,self代表Worker线程自身,即Worker线程的全局对象。因此,等同于下面两种写法。

// 写法一
this.addEventListener('message', function (e) {
  this.postMessage('You said: ' + e.data);
}, false);

// 写法二
addEventListener('message', function (e) {
  postMessage('You said: ' + e.data);
}, false);

除了使用self.addEventListener()指定监听函数,也可以使用self.onmessage指定。监听函数的参数是一个事件对象,它的data属性包含主线程发来的数据。self.postMessage()方法用来向主线程发送消息。

close() 函数允许Worker将自己终止。要注意的是,在Worker对象上没有定义任何API用于检测是否Worker已经将自己关闭,也没有类似onclose这样的事件处理程序属性。如果在一个已经关闭的Worker上调用 postMessage() 方法,那么消息会被无声无息地丢弃,而且也不会有任何错误抛出。因此,如果Worker想要使用 close() 方法将自己关闭,那么最好是先传递诸如“关闭”这样的消息。

根据主线程发来的数据,Worker 线程可以调用不同的方法,下面是一个例子。

self.addEventListener('message', function (e) {
  var data = e.data;
  switch (data.cmd) {
    case 'start':
      self.postMessage('WORKER STARTED: ' + data.msg);
      break;
    case 'stop':
      self.postMessage('WORKER STOPPED: ' + data.msg);
      self.close(); // Terminates the worker.
      break;
    default:
      self.postMessage('Unknown command: ' + data.msg);
  };
}, false);

2.3 WorkerGlobalScope 全局对象

WorkerGlobalScope 对象是Worker线程的全局对象,它有所有核心js全局对象拥有的那些熟悉,诸如 JSON对象、isNaN() 函数和 Date()构造函数。除此之外,WorkerGlobalScope 对象还有客户端Window对象拥有的一些如下属性:

  • self是对全局对象自身的引用。
  • 计时器方法:setTimeout()、clearTimeout()、setInterval() 以及 clearInterval()。
  • location属性,描述传递给 Worker() 构造函数的URL。和Window对象的location属性一样,此属性指向一个Location对象。该对象有href、protocal、host、hostname、port、pathname、search以及hash属性。在Worker中,这些属性都是只读的。
  • navigator属性,跟 Window.navigator 属性类似。
  • addEventListener() 和 removeEventListener()
  • onerror 属性,可以将它设置为一个错误事件处理程序,错误消息、URL以及行号会作为三个字符串参数传递给该处理程序。如果该处理程序返回false,则表示错误已经处理,不应该再将其当成一个Worker对象上的error事件传播了。

最后,WorkerGlobalScope 对象还包含客户端js一些重要的构造函数对象。其中包括 XMLHttpRequest(),以及 Worker() 构造函数,Worker可以通过它创建它们自己的Worker线程。

2.4 Worker 加载脚本

Worker使用 importScripts() 方法来加载任何需要的库代码。

// 在开始工作前,先载入需要的类、工具函数
importScripts('collections/Set.js', 'utils/base64.js');

importScripts() 是一个同步的方法,接受一个或者多个URL参数,每个URL都需指向一个js代码文件。相对地址的URL以传递给 Worker() 构造函数的URL为参照。它会按照指定的顺序依次载入并运行这些js文件。如果载入脚本的时候抛出了网络错误,或者在执行的时候抛出了错误,那么剩下的脚本都不会载入和运行。通过  importScripts() 方法载入的脚本自身还可以调用  importScripts() 方法载入它需要的文件。但是, importScripts() 方法不会试图去跟踪哪些脚本已经载入了,也不会去防止循环依赖的问题。

三、数据通信

前面说过,主线程与 Worker 之间的通信内容,可以是文本,也可以是对象。需要注意的是,这种通信是拷贝关系,即是传值而不是传址,Worker 对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给 Worker,后者再将它还原。

主线程与 Worker 之间也可以交换二进制数据,比如 File、Blob、ArrayBuffer 等类型,也可以在线程之间发送。下面是一个例子。


// 主线程
var uInt8Array = new Uint8Array(new ArrayBuffer(10));
for (var i = 0; i < uInt8Array.length; ++i) {
  uInt8Array[i] = i * 2; // [0, 2, 4, 6, 8,...]
}
worker.postMessage(uInt8Array);

// Worker 线程
self.onmessage = function (e) {
  var uInt8Array = e.data;
  postMessage('Inside worker.js: uInt8Array.toString() = ' + uInt8Array.toString());
  postMessage('Inside worker.js: uInt8Array.byteLength = ' + uInt8Array.byteLength);
};

但是,拷贝方式发送二进制数据,会造成性能问题。比如,主线程向 Worker 发送一个 500MB 文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript 允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做Transferable Objects。这使得主线程可以快速把数据交给 Worker,对于影像处理、声音处理、3D 运算等就非常方便了,不会产生性能负担。

如果要直接转移数据的控制权,就要使用下面的写法。


// Transferable Objects 格式
worker.postMessage(arrayBuffer, [arrayBuffer]);

// 例子
var ab = new ArrayBuffer(1);
worker.postMessage(ab, [ab]);

四、同页面的 Web Worker(加载本地js路径的Worker)

通常情况下,Worker 载入的是一个单独的 JavaScript 脚本文件,但是也可以载入与主线程在同一个网页的代码。

<!DOCTYPE html>
  <body>
    <script id="worker" type="app/worker">
      addEventListener('message', function () {
        postMessage('some message');
      }, false);
    </script>
  </body>
</html>

上面是一段嵌入网页的脚本,注意必须指定<script>标签的type属性是一个浏览器不认识的值,上例是app/worker

然后,读取这一段嵌入页面的脚本,用 Worker 来处理。

var blob = new Blob([document.querySelector('#worker').textContent]);
var url = window.URL.createObjectURL(blob);
var worker = new Worker(url);

worker.onmessage = function (e) {
  // e.data === 'some message'
};

上面代码中,先将嵌入网页的脚本代码,转成一个二进制对象,然后为这个二进制对象生成 URL,再让 Worker 加载这个 URL。这样就做到了,主线程和 Worker 的代码都在同一个网页上面。

另外一种示例代码:

// worker线程代码
let script = `self.onmessage = function (e) { 
  console.log({data: e.data})
  postMessage('我很好!');
}`;

let workerBlob = new Blob([script], {type: "text/javascript"});
let url = URL.createObjectURL(workerBlob);
let worker = new Worker(url);
worker.postMessage('你好吗?');
worker.onmessage = function(e) {
    console.log({e})
}
worker.onerror = function(error) {
    console.log({error})
}

五、实例:Worker 线程完成轮询

有时,浏览器需要轮询服务器状态,以便第一时间得知状态改变。这个工作可以放在 Worker 里面。

function createWorker(f) {
  var blob = new Blob(['(' + f.toString() +')()']);
  var url = window.URL.createObjectURL(blob);
  var worker = new Worker(url);
  return worker;
}

var pollingWorker = createWorker(function (e) {
  var cache;

  function compare(new, old) { ... };

  setInterval(function () {
    fetch('/my-api-endpoint').then(function (res) {
      var data = res.json();

      if (!compare(data, cache)) {
        cache = data;
        self.postMessage(data);
      }
    })
  }, 1000)
});

pollingWorker.onmessage = function () {
  // render data
}

pollingWorker.postMessage('init');

上面代码中,Worker 每秒钟轮询一次数据,然后跟缓存做比较。如果不一致,就说明服务端有了新的变化,因此就要通知主线程。

六、实例: Worker 新建 Worker

Worker 线程内部还能再新建 Worker 线程(目前只有 Firefox 浏览器支持)。下面的例子是将一个计算密集的任务,分配到10个 Worker。

主线程代码如下。

var worker = new Worker('worker.js');
worker.onmessage = function (event) {
  document.getElementById('result').textContent = event.data;
};

Worker 线程代码如下。

// worker.js

// settings
var num_workers = 10;
var items_per_worker = 1000000;

// start the workers
var result = 0;
var pending_workers = num_workers;
for (var i = 0; i < num_workers; i += 1) {
  var worker = new Worker('core.js');
  worker.postMessage(i * items_per_worker);
  worker.postMessage((i + 1) * items_per_worker);
  worker.onmessage = storeResult;
}

// handle the results
function storeResult(event) {
  result += event.data;
  pending_workers -= 1;
  if (pending_workers <= 0)
    postMessage(result); // finished!
}

上面代码中,Worker 线程内部新建了10个 Worker 线程,并且依次向这10个 Worker 发送消息,告知了计算的起点和终点。计算任务脚本的代码如下。

// core.js
var start;
onmessage = getStart;
function getStart(event) {
  start = event.data;
  onmessage = getEnd;
}

var end;
function getEnd(event) {
  end = event.data;
  onmessage = null;
  work();
}

function work() {
  var result = 0;
  for (var i = start; i < end; i += 1) {
    // perform some complex calculation here
    result += 1;
  }
  postMessage(result);
  close();
}

七、API

7.1 主线程

浏览器原生提供Worker()构造函数,用来供主线程生成 Worker 线程。

var myWorker = new Worker(jsUrl, options);

Worker()构造函数,可以接受两个参数。第一个参数是脚本的网址(必须遵守同源政策),该参数是必需的,且只能加载 JS 脚本,否则会报错。第二个参数是配置对象,该对象可选。它的一个作用就是指定 Worker 的名称,用来区分多个 Worker 线程。

// 主线程
var myWorker = new Worker('worker.js', { name : 'myWorker' });

// Worker 线程
self.name // myWorker

Worker()构造函数返回一个 Worker 线程对象,用来供主线程操作 Worker。Worker 线程对象的属性和方法如下。

  • Worker.onerror:指定 error 事件的监听函数。
  • Worker.onmessage:指定 message 事件的监听函数,发送过来的数据在Event.data属性中。
  • Worker.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
  • Worker.postMessage():向 Worker 线程发送消息。
  • Worker.terminate():立即终止 Worker 线程。

7.2 Worker 线程

Web Worker 有自己的全局对象,不是主线程的window,而是一个专门为 Worker 定制的全局对象。因此定义在window上面的对象和方法不是全部都可以使用。

Worker 线程有一些自己的全局属性和方法。

  • self.name: Worker 的名字。该属性只读,由构造函数指定。
  • self.onmessage:指定message事件的监听函数。
  • self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
  • self.close():关闭 Worker 线程。
  • self.postMessage():向产生这个 Worker 线程发送消息。
  • self.importScripts():加载 JS 脚本。

八、利用MessageChannel实现两个 Worker 之间通信

main.html

<script>
        var w1 = new Worker("worker1.js");
        var w2 = new Worker("worker2.js");
        var ch = new MessageChannel();
        w1.postMessage("initial port",[ch.port1]);
        w2.postMessage("initial port",[ch.port2]);
        w2.onmessage = function(e){
            console.log(e.data);
        }
<script>

worker1.js

var port;
   onmessage = function(e){
    if(e.data == "initial port"){
        port = e.ports[0];
    }else{
        setTimeout(function(){
            port.postMessage("this is from worker1")
        },2000)
      }
   }

worker2.js

var port;
    onmessage = function(e){
    if(e.data == "initial port"){
        port = e.ports[0];
        port.onmessage = function(e){
            postMessage(e.data)
        }
       }
   }

最终输出:this is from worker1

传递的路径为:w1=> ch1 => ch2 => w2

九、兼容性

IE9+

参考

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Web Worker 用法 的相关文章

  • Twisted 的 Deferred 和 JavaScript 中的 Promise 一样吗?

    我开始在一个需要异步编程的项目中使用 Twisted 并且文档非常好 所以我的问题是 Twisted 中的 Deferred 与 Javascript 中的 Promise 相同吗 如果不是 有什么区别 你的问题的答案是Yes and No
  • 使用 Javascript 在 Imacros 中循环

    我如何使用 javascript 循环 imm imacros 脚本 我搜索了一下 发现了这个 for i 0 i lt n i iimPlay marconame iim 但当我使用它时 我的浏览器 Firefox 18 挂起 for i
  • 为什么 jQuery 点击事件会多次触发

    我这里有这个示例代码http jsfiddle net DBBUL 10 http jsfiddle net DBBUL 10 document ready function creategene click function confir
  • 将一个文本框的内容复制到另一个文本框

    假设在文本框中输入了一个条目 是否可以在第二个文本框中保留相同的输入文本 如果是这样 这是如何完成的
  • 将 jquery-mobile 与 Webpack 结合使用

    我正在尝试使用 webpack 加载 jquery mobile 但到目前为止还没有运气 我知道 jquery mobile 依赖于 jquery ui 而 jquery ui 又依赖于 jquery 如何在 Webpack 中设置这样的场
  • 将音频与视频流合并 Node.js

    我正在创建 YouTube 视频下载器并且正在使用ytdl core库 它无法下载带有音频的高质量视频 因为 youtube 将其放在另一个文件中 但我需要将其全部下载到一个文件中 我已经这样做了 app get download asyn
  • 禁用 JavaScript 中的右键单击

    当我尝试禁用右键单击时 它不起作用 我尝试使用下面的代码 document onclick function e console log e button if e button 2 e preventDefault return fals
  • 如何在 d3 js 中突出显示从根到选定节点的路径?

    我使用 d3 js 创建了一棵树 现在我创建了一个下拉菜单 其中包含树中所有节点的列表 现在 从下拉菜单中选择一个节点时 我想突出显示从根到该特定节点的路径 这个怎么做 首先创建一个 flatten 函数 它将分层数据变成一个 n 数组 f
  • 在 MVC Razor 中的 C# 和 Javascript 之间共享常量

    我想在服务器上的 C 和客户端上的 Javascript 中都使用字符串常量 我将常量封装在 C 类中 namespace MyModel public static class Constants public const string
  • 如何记录返回的事件发射器

    如何记录所发出的事件stream返回于MyFunc 与 JSDoc MyFunc description param Object opts description return Stream description function My
  • JavaScript 动画平滑滚动

    默认情况下 当您有这样的片段链接时 a href some url some fragment some text a 浏览器立即向下滚动到该片段 我该如何编程才能使用标准 JS 顺利地向下移动到该片段 这是一个例子 Example htt
  • 如何改变HTML5视频的播放速度?

    如何更改 HTML5 中的视频播放速度 我查过视频标签的属性 https www w3schools com html html5 video asp在 w3school 但无法做到这一点 根据这个网站 http www chipwreck
  • 如何清除WebGL中的矩形区域?

    WebGL 有一个clear清除整个表面的方法 清除表面的特定矩形的最佳方法是什么 例如 我想将一个从 50 50 开始的 100x100 像素框设置为全零 ARGB 0 0 0 0 我现在能想到的就是用一个写入零的片段着色器绘制一个四边形
  • 如何滚动到div内的元素?

    我有一个滚动的div我想在点击它时发生一个事件 它会强制执行此操作div滚动以查看内部元素 我写的JavasCript是这样的 document getElementById chr scrollIntoView true 但这会在滚动时滚
  • React无限滚动scrollableTarget动态获取id?

    我在我的项目中使用react infinite scroll component 如何让scrollableTarget动态获取item id 我试过这样scrollableTarget item id 但它不起作用 必须与该 div 具有
  • 是否可以使用打字稿映射类型来创建接口的非函数属性类型?

    所以我正在研究 Typescript 的映射类型 是否可以创建一个接口来包装另一种类型 从而从原始类型中删除函数 例如 interface Person name string age number speak void type Data
  • Jquery:选择菜单以显示和隐藏某些div元素

    我正在创建一个选择菜单 根据所选选项显示和隐藏某些 div 像这样的东西
  • 加载另一个 JS 脚本后加载

    这是我的代码 very big js file lots of html stuff 问题是 这些是异步加载的 有没有办法等待第二个脚本直到第一个脚本加载 如果您使用 jQuery 有一个非常简单的方法可以通过获取脚本 https api
  • React Native - 跨屏幕传递数据

    我遇到了一些麻烦react native应用程序 我不知道如何跨屏幕传递数据 我意识到还有其他类似的问题在 SO 上得到了回答 但是这些解决方案对我来说不起作用 我正在使用StackNavigator 这是我的设置App js file e
  • 如何更改订阅值?使用 rxJS

    我正在创建一个计时器 需要你的帮助 我刚刚学习 Angular 和 rxJS 对此我有一些疑问 我正在创建一个具有启动 停止 暂停 重置功能的计时器 并且 btn Reset 必须将我的计时器 暂停 到 300 毫秒 怎么做 D 我的启动定

随机推荐

  • springboot后台获取不到前台Vue日期问题解决

    一 实体类字段写法如下 JsonFormat pattern yyyy MM dd timezone GMT 8 private Date sendTime Vue使用element ui写法
  • 4.2、Flink任务怎样读取文件中的数据

    目录 1 前言 2 readTextFile 已过时 不推荐使用 3 readFile 已过时 不推荐使用 4 fromSource FileSource 推荐使用 1 前言 思考 读取文件时可以设置哪些规则呢 1 文件的格式 txt cs
  • (二)程序语言设计基础

    目录 1 程序设计语言概述 1 1 基本概念 1 1 1 低级语言和高级语言 1 1 2 编译程序和解释程序 1 1 3 程序设计语言的定义 1 1 4 程序设计语言的分类 1 2 程序设计语言的基本成分 1 2 1 数据成分 1 2 2
  • 2022最新android设备uuid、udid使用教程​

    前言 udid UDID是Unique Device Identifier的缩写 中文意思是设备唯一标识 uuid UUID是Universally Unique Identifier的缩写 中文意思是通用唯一识别码 简言之 udid对应某
  • elasticsearch 中text与keyword的区别

    创建索引 PUT ellis mappings properties name type text fields keyword type keyword ignore above 256 age type long 我们可以看到name类
  • VBA常用语法

    最近接触了一下VBA编程 才知道Excel还能编程 而且还如此强大 真的是惊呆了 话不多说 先了解一下VBA常用的语法吧 1 基础语法 高级for循环 Function deleteArrayByIndex list As String D
  • oracle获取随机记录

    oracle获取随机记录 select from select from ford car order by dbms random value where rownum lt 1001
  • 【vision transformer】DETR原理及代码详解(三)

    transformer 端到端目标检测DETR项目实践及代码详解 Paddle Detr git PaddleViT object detection DETR at develop BR IDL PaddleViT GitHub 数据集及
  • Redis SDS简单动态字符串

    结构体定义 本质上说就是用C语言来实现基本的面向对象 来对底层的字符串进行表示 方便上层使用 为调用者减少负担 typedef char sds struct sdshdr int len int free char buf 举例常用操作
  • 搭建JMeter分布式测试环境

    分布式测试概述 现在我们来了解如何使用多台机器来执行压力测试 也就是所谓的分布式测试 当我们模拟大量的并发虚拟用户时 比如我们要起10万 100万甚至更多的并发用户时 一台负载机器可能就满足不了我们需要的用户量 此时 就需要使用多台主机搭建
  • Git入门--自定义标签

    忽略特殊文件 忽略某些文件时 需要编写 gitignore gitignore文件本身要放到版本库里 并且可以对 gitignore做版本管理 配置别名 git config global alias co checkout 用co来代替c
  • FFmpeg源码分析:av_register_all()注册封装器与解封装器

    FFmpeg中av register all 函数用于注册所有muxers demuxers与protocols FFmpeg4 0以前是用链表存储muxer demuxer FFmpeg4 0以后改为数组存储 并且av register
  • SPP原理和代码

    空间金字塔池化 Spatial Pyramid Pooling SPP 原理和代码实现 Pytorch 一 为什么需要SPP 首先需要知道为什么需要SPP 我们都知道卷积神经网络 CNN 由卷积层和全连接层组成 其中卷积层对于输入数据的大小
  • 众享比特董事长严挺:数字藏品在国内有三大发展趋势

    2022年11月2日 巴比特主办的温州元宇宙月系列活动之 数字藏品 虚拟人 元宇宙营销新策略 论坛在温州召开 众享比特董事长严挺 众享链网发起人严挺出席论坛并进行主题为 元宇宙在国内落地的一些实践分享 的演讲 温州元宇宙主题月秉承 拥抱数字
  • Hyperledger fabric2.4 搭建自己的网络

    1 使用cryptogen工具生成证书 1 1 将fabric samples bin目录下的二进制文件复制到 usr local bin目录 以便全局使用这些命令 cd fabric samples bin cp usr local bi
  • 那些你可能遇到的 Linux 命令?什么,你还不知道?赶紧收藏?完善中!

    文章目录 一 Linux 进程 1 通过进程名查找进程号 1 1 ps aux ps ef diff 1 2 ps aux ps aux 什么 它们不一样 1 3 grep awk 取出进程号 取出进程号并 Kill 2 通过进程号查看进程
  • LINUX应用和驱动交互的四种方式

    Linux开发中 应用读取数据时往往会遇到驱动尚未获得有效数据的情况 所以需要采用适合的同步方式 1 非阻塞方式 非阻塞方式 顾名思义就是不管数据是否准备好 驱动都会返回结果 采用这种方式就需要应用不停地重复查询 查询硬件的线程就会一直都占
  • Centos7 升级openssl-1.1.1s及openssh-9.1p1(附脚本)

    主要是上个月openssl出现了漏洞 因此要对服务器的进行升级 建议如果没问题还是尽量别升级 主要步骤是2 脚本内容也只包含升级 1和3是开启和关闭telnet 不建议使用telnet 1 安装和启动telnet 实际中我没使用telnet
  • 数据结构前言

    一 什么是数据结构 数据结构是计算机存储 组织数据的方式 数据结构是指相互之间存在一种或多种特定关系的数据元素的集合 上面是百度百科的定义 通俗的来讲数据结构就是数据元素集合与数据元素集合或者数据元素与数据元素之间的组成形式 举个简单明了的
  • Web Worker 用法

    一 概述 JavaScript 语言采用的是单线程模型 也就是说 所有任务只能在一个线程上完成 一次只能做一件事 前面的任务没做完 后面的任务只能等着 随着电脑计算能力的增强 尤其是多核 CPU 的出现 单线程带来很大的不便 无法充分发挥计