性能优化之使用vue-worker插件(基于Web Worker)开启多线程运算提高效率

简介: 性能优化之使用vue-worker插件(基于Web Worker)开启多线程运算提高效率

什么是Web Worker

15年前,也就是2008年,html第五版html5发布,这一版的发布,提供了不少新的好用的功能,如:

  • Canvas绘图
  • 拖拽drag
  • websocket
  • Geolocation
  • webworker
  • 等...

笔者之前说过:一项新技术新的技术方案的提出,一定是为了解决某个问题的,或者是对某种方案的优化

那么Web Worker这个新技术解决了什么问题?有哪些优化价值呢?

让我们继续往下看...

官方定义

Web Worker 为 Web 内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。此外,他们可以使用XMLHttpRequest执行 I/O (尽管responseXML和channel属性总是为空)。一旦创建,一个 worker 可以将消息发送到创建它的 JavaScript 代码,通过将消息发布到该代码指定的事件处理程序(反之亦然)......

官方MDN地址: https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers

乍一看这段话,好像懂了(Web Worker和线程有关),又好像没懂。但是我们能看到一个加粗的关键字:线程

那么,新的问题来了,什么是线程?

当我们去学习一个知识点 A的时候,我们会发现知识点A是由 a1、a2、a3、a4组合而成的,所以我们要继续下钻,去搞懂 a1、a2、a3、a4分别是什么意思。这样才能更好的理解知识点 A的含义内容。

什么是线程

线程基本八股文定义不赘述,大家可以将线程理解成为一个打工仔,每天的工作就是解析翻译并执行代码,像搬砖一样,不过一次只能搬一块砖,后面有砖,不好意思,你等会儿,等我把这个砖搬完了再搬你们。

线程道人朗声道:尔等砖头列队稍后,待老夫一块块搬!(js中的任务队列

js单线程语言,生来便是! java平常写代码也是 单线程的操作,不过 单线程有时候不太够用,于是 java中也提供了 多线程的操作入口,比如: Thread类Runnable接口Callable接口;大多数语言都是类似的, python也是的啊, python写代码平常也是 单线程,另也提供了 threading模块让程序员可以去做 多线程操作

为何js要设计成单线程呢?

  • 符合大致趋势
  • 这与js的工作内容有关:js只是用来去做一些用户交互,并呈现效果内容。
  • 试想,如果js是多线程,线程一将dom元素的背景色改成红色,线程二将dom元素的背景色改为绿色,那么,到底上红色还是绿色呢?
  • 不过后来人们发现,某些情况下,前端如果能做多线程的操作,将会大大提升开发效率
  • 于是Web Worker就应运而生了
  • Web Worker可以创建另外的线程去做一些操作,操作不影响js主线程(比如UI渲染
  • 本来只有一个js主线程搬砖,现在又过来好几个js辅助线程一块帮忙搬砖,那肯定效率高啊!
有点道友问,那如果主线程操作dom,然后在Web worker创建的辅助线程中也去操作dom呢?最终结果听谁的啊???回答:Web work创建的线程中没有document全局文档对象,所以无法操作dom,另外,也不会这样做的
  • 大家这样理解:在实际开发场景中Web Worker主要,多数,应用在前端一些复杂中运算
  • 而大家都知道一些复杂的运算,基本上交由后端去处理(实际上复杂的运算操作,后端也会看情况去开启多线程操作的)
  • 这样说来,Web Worker的作用就是把后端进行的多线程操作运算拿到前端了
  • 工作中一些数据的加工、计算、组装逻辑操作,常常是由后端来干;但是在某些情况下,如果前端去做的话,效率或许更高一些

所以Web Worker这个新技术的价值是什么呢?

Web worker创建辅助线程、帮助前端主线程进行复杂耗时的计算

一个人手不够用,那就多摇几个人。

Web worker创建的一些辅助线程,分别去帮主线程分担一些复杂的、耗时的js运算,这样的话,主线程后续的代码执行就不会阻塞,当辅助线程计算出复杂耗时运算结果后,再与主线程通信,将计算出的结果告知主线程。

Web Worker新技术价值,简而言之:提升前端代码运算执行效率

关于Web worker的原生语法,诸如:

// 创建一个Web worker
var myWorker = new Worker('worker.js');

// 使用Web worker发送消息
worker.postMessage(params)

// 使用Web worker接收消息
worker.onmessage = function(e) {
    console.log(e.data)
}

// 等等...

Web worker的原生语法,笔者不赘述了,大家可自行去MDN上的Web Worker去查看,

为什么不说呢?因为我们工作中开发代码,基本上都是使用框架,在框架中直接写原生的Web worker有许多的边界异常或者其他的情况需要控制。以vue框架为例,我们不能直接写Web Worker,需要使用Webpack中的worker-loader插件去解析Web worker,并且在vue.config.js中去做相应配置。

嗯,有些麻烦。

在这个情况下,基于Web Worker进行封装的插件库vue-worker,就闪亮登场了。

简单、好用、便于理解

这里不提Web worker的原生基本语法不是说大家不用看了,看还是要看的,只不过篇幅原因(懒),这里就不赘述了。

Web Worker的应用场景

如果大家只是写增删改查的业务代码,Web Worker用的的确非常少

工作中那些需要进行复杂耗时的计算的逻辑代码,都可以由前端使用 Web Worker进行计算。但是复杂耗时的计算基本上都是交由后端进行。这个普遍认知下导致其使用的比较少。

大概有以下场景:

  • 加密解密数据(加密解密笔者之前接触的是NodeRSA、md5、crypto
  • 提前获取数据,比如提前发送ajax请求获取接口的一些图片、数值等相关数据
  • 将耗时运算交由Web Work处理(笔者之前做的就是这个)
不过使用的是 vue-worker插件(基于 Web Worker封装的插件)

vue-worker(基于Web worker封装的一款不错的插件)

当我们找到一款还不错的插件的时候,我们首先去npm官网上看看这个插件的下载量如何,以及GitHubstar数量多少。

npm地址: https://www.npmjs.com/package/vue-worker?activeTab=versions

vue-worker下载量截图:

111.png

好少啊,一共也才不到3000次下载量,这里的下载量少是因为,应用场景不多,所以大家使用的也是少,接下来谈谈自己曾经使用Web worker的这个场景

曾经应用场景

笔者之前做一个项目,页面上有很多的输入框,里面的输入框中需要填写硬件采集的:压力、温度、比热容、质量大小等很多参数,当点击计算按钮时,会把这些参数进行计算,得出的结果,以供工作人员进行工作参考。

相当于一个计算器,只不过计算时间会很长

本来说是把这个计算过程交给后端计算,只不过当时后端的同事有事情,请假一周。但是工作不能停下啊

于是笔者就想能不能前端计算呢?

经过一系列调研(谷歌一下),找到了vue-worker插件

最终是由笔者这个前端去做的这个计算,时间挺好,产品喜笑颜开

使用步骤

1.下载依赖包

cnpm i vue-worker --save

2.在入口文件中引入

import Vue from 'vue'
import VueWorker from 'vue-worker' // Web worker插件
Vue.use(VueWorker)

3.使用

接下来,笔者举两个例子,更加便于大家理解

案例一 主线程渲染dom、辅助线程进行计算

需求:

  • 点击按钮进行计算,计算执行两个UI操作
  • 第一个UI操作,计算斐波那契数fib(44)的值,且统计计算所用的时长,并写入到页面上
  • 第二个UI操作,每隔0.1秒,更新页面上h2标签的内容值
  • 要求两个操作不阻塞,不能出现后一个UI操作要等待前一个UI操作的情况
  • 因为斐波那契是递归执行,是一个比较耗时的操作fib(44)
  • 那就想办法不让这个耗时的操作堵塞住任务队列

我们使用vue-worker提供的方法:this.$worker.run(func, [args]?)

写法如下:

html

<h1>开启一个线程运算用$worker.run方法</h1>
<br />
<el-button
  @click="openOneThread"
  type="success"
  plain
  size="small"
  style="margin-bottom: 16px"
  >计算斐波那契数列值和用时,以及渲染页面两个任务</el-button
>
<div>
  斐波那契值为:<span class="bold">{{ fibRes }}</span>
  <i v-show="btnLoading" class="el-icon-loading"></i>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 执行用时:
  <i v-show="btnLoading" class="el-icon-loading"></i>
  <span class="bold">{{ fibTime }}</span>
  毫秒
</div>

js

// data
worker: null,
btnLoading: false,
fibNum: 44,
fibRes: null, // 斐波那契计算的结果
fibTime: null, // 斐波那契计算用时

// methods
openOneThread() {
  /* 第一个UI操作 */
  this.btnLoading = true;
  this.worker = this.$worker // this.$worker.run(func, [args]?) 一次性的,自动销毁
    .run(
      (n) => {
        // 注意这里的函数是内部另一个线程空间的,不能从外部引入过来(内存空间隔离)
        function fib(n) {
          if ((n == 1) | (n == 2)) {
            return 1;
          } else {
            return fib(n - 1) + fib(n - 2);
          }
        }
        let start = Date.now(); // console.time()和console.timeEnd()直接拿不到值,就换种方式
        let res = fib(n);
        let end = Date.now(); // window.performance.now()也不能用,因为没window对象
        return [res, end - start]; // 返回数组,第一项是fib(44)的值,第二项是fib(44)递归计算用时
      },
      [this.fibNum] // 参数,从这里传递进去,数组形式
    )
    .then((res) => {
      console.log("then", res); // 另一个线程执行完以后就能拿到结果了
      this.fibRes = res[0];
      this.fibTime = res[1];
      this.btnLoading = false;
    })
    .catch((err) => {
      console.log("err", err);
      this.btnLoading = false;
    });
  /* 第二个UI操作 */
  let h2Dom = this.$refs.renderH2;
  let n = 0;
  let timer = setInterval(() => {
    if (n >= 60) {
      clearInterval(timer);
    } else {
      n++;
      h2Dom.innerHTML = n;
    }
  }, 100);
  // 使用web worker插件vue-work的确可以做到不阻塞
},

效果图

222.gif

案例二 开启三个辅助线程进行计算看时间

案例一,已经可以看到Web Worker优势了。接下来,我们再举个例子。

需求:需要计算3个fib(30),如果我们使用Promise,写法是这样的:

Promise.all进行计算

async usePromiseFn() {
  function asyncOne() {
    let async1 = new Promise(async (resolve, reject) => {
      function fib(n) {
        if ((n === 1) | (n === 2)) {
          return 1;
        } else {
          return fib(n - 1) + fib(n - 1);
        }
      }
      resolve(fib(30));
    });
    return async1;
  }

  function asyncTwo() {
    let async2 = new Promise(async (resolve, reject) => {
      function fib(n) {
        if ((n === 1) | (n === 2)) {
          return 1;
        } else {
          return fib(n - 1) + fib(n - 1);
        }
      }
      resolve(fib(30));
    });
    return async2;
  }

  function asyncThree() {
    let async3 = new Promise(async (resolve, reject) => {
      function fib(n) {
        if ((n === 1) | (n === 2)) {
          return 1;
        } else {
          return fib(n - 1) + fib(n - 1);
        }
      }
      resolve(fib(30));
    });
    return async3;
  }

  console.time("使用Promise搭配aysnc和await");

  // let paramsArr = [asyncOne()]; // 计算一个大概在3秒左右(计算一次刷新一次页面,精确一些)
  let paramsArr = [asyncOne(), asyncTwo(), asyncThree()]; // 计算三个耗时任务大概在9秒左右

  let res = await Promise.all(paramsArr);
  console.timeEnd("使用Promise搭配aysnc和await");
  console.log("结果", res);
},
},

使用Promise.all方法去计算3个fib值,用时在9秒左右,的确是有些慢。那么,我们使用Web Worker方式呢?

此外,使用Promise.all控制台也会有警告提醒:[Violation] 'click' handler took 8822ms

333.png

意思是: click事件中执行的程序 耗时过长,看到没,如果使用 js主线程去进行复杂计算,浏览器都看不下去了...

再一个,大家在Promise执行的时候,去选中页面上的文字,发现选中不了!就像卡住了一样!从这个方面也说明,js主线程不适合执行复杂的运算,阻塞...

Web Worker进行计算

这里使用this.$worker.create方法,搭配this.worker2.postAll方法

代码写法如下

  created() {
    // 1. 定义线程所用的消息函数数组
    const actions = [
      {
        message: "fn1", // message消息与func函数执行为映射关系
        func: (params1, params2) => {
          console.log("params参数-->", params1, params2);
          function fib(n) {
            if ((n == 1) | (n == 2)) {
              return 1;
            } else {
              return fib(n - 1) + fib(n - 2);
            }
          }
          return fib(30);
        },
      },
      {
        message: "fn2",
        func: () => {
          function fib(n) {
            if ((n == 1) | (n == 2)) {
              return 1;
            } else {
              return fib(n - 1) + fib(n - 2);
            }
          }
          return fib(30);
        },
      },
      {
        message: "fn3",
        func: () => {
          function fib(n) {
            if ((n == 1) | (n == 2)) {
              return 1;
            } else {
              return fib(n - 1) + fib(n - 2);
            }
          }
          // throw "一个报错挂了,其他的也跟着挂了,走.catch"; // 抛出错误(的确很像Promise.all())
          return fib(30);
        },
      },
    ];
    // 2. 根据消息函数数组去create创建一个worker,并存到data变量中去,以便于后续随时使用
    this.worker2 = this.$worker.create(actions);
  },
 

// 点击触发noParamsFn方法执行
// 使用多个线程
noParamsFn() {
  this.loadingOne = true;
  console.time("多个线程计算用时1");
  this.worker2
    .postAll()
    .then((res) => {
      console.timeEnd("多个线程计算用时1");
      console.log("res", res); // 结果是一个数组 [267914296, 433494437, 701408733]
      this.loadingOne = false;
    })
    .catch((err) => {
      console.timeEnd("多个线程计算用时1");
      console.log("err", err);
      this.loadingOne = false;
    });
},

我们看一下效果图

444.gif

看到没有。只用了53毫秒

  • 使用主线程去计算3个fib(30)的值,需要将近9秒的时间
  • 而使用Web Worker去创建三个辅助线程分别去运算fib(30)所需要的时间,只需要50多毫秒

性能提升了100多倍!

这个案例才真正的体现了,Web Worker开启多线程运算提高效率的强大!

大家可以去笔者的个人网站上去看完整的效果图:http://ashuai.work:8888/#/myWork

Web WorkerHTML5提出的 规范,主流浏览器都已经得到了兼容。 IE就忽略吧

附上案例完整代码

篇幅有限,一些vue-worker插件常用的使用语法细节,写在代码中了,大家复制粘贴即可使用

<template>
  <div class="threadWrap">
    <h1>开启一个线程运算用$worker.run方法</h1>
    <br />
    <el-button
      @click="openOneThread"
      type="success"
      plain
      size="small"
      style="margin-bottom: 16px"
      >计算斐波那契数列值和用时,以及渲染页面两个任务</el-button
    >
    <div>
      斐波那契值为:<span class="bold">{{ fibRes }}</span>
      <i v-show="btnLoading" class="el-icon-loading"></i>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 执行用时:
      <i v-show="btnLoading" class="el-icon-loading"></i>
      <span class="bold">{{ fibTime }}</span>
      毫秒
    </div>
    <br />
    <div class="UI">
      <span>不阻塞后续的代码执行:</span>
      <h2 ref="renderH2"></h2>
    </div>
    <br />
    <br />
    <h1>开启多个线程使用$worker.create、postAll方法</h1>
    <br />
    <el-button
      @click="noParamsFn"
      type="success"
      plain
      size="small"
      style="margin-bottom: 12px"
      :loading="loadingOne"
      >不传参都执行一次</el-button
    >
    <el-button
      @click="byMessageNameStrFn"
      type="success"
      plain
      size="small"
      style="margin-bottom: 12px"
      :loading="loadingTwo"
      >根据message的名字指定谁执行(字符串形式)</el-button
    >
    <el-button
      @click="byMessageNameObjParamsFn"
      type="success"
      plain
      size="small"
      style="margin-bottom: 12px"
      :loading="loadingThree"
      >根据message的名字指定谁执行(对象形式可传参)</el-button
    >
    <div class="info">F12请打开控制台查看--></div>
    <br />
    <h1>不使用多线程,使用Promise.all太耗时啦!</h1>
    <br />
    <el-button
      @click="usePromiseFn"
      type="success"
      plain
      size="small"
      style="margin-bottom: 12px"
      >Promise执行多个任务</el-button
    >
    <div class="info">F12请打开控制台查看--></div>
  </div>
</template>

<script>
export default {
  name: "myWorkName",
  data() {
    return {
      worker: null,
      btnLoading: false,
      fibNum: 44,
      fibRes: null,
      fibTime: null,
      /****/
      loadingOne: false,
      loadingTwo: false,
      loadingThree: false,
      worker2: null,
    };
  },
  methods: {
    /**
     * 需求:点击数据计算进行两个操作
     *      第一个UI操作,计算斐波那契数fib(44)的值,且统计计算所用的时长,并写入到页面上
     *      第二个UI操作,每隔0.1秒,更新页面上h2标签的内容值
     *      要求两个操作不阻塞,不能出现后一个UI操作要等待前一个UI操作的情况
     *      因为斐波那契是递归执行,是一个比较耗时的操作fib(44)约需要近8秒的计算时间
     * */
    openOneThread() {
      /* 第一个UI操作 */
      this.btnLoading = true;
      this.worker = this.$worker // this.$worker.run(func, [args]?) 一次性的,自动销毁
        .run(
          (n) => {
            // 注意这里的函数是内部另一个线程空间的,不能从外部引入过来(内存空间隔离)
            function fib(n) {
              if ((n == 1) | (n == 2)) {
                return 1;
              } else {
                return fib(n - 1) + fib(n - 2);
              }
            }
            let start = Date.now(); // console.time()和console.timeEnd()直接拿不到值,就换种方式
            let res = fib(n);
            let end = Date.now(); // window.performance.now()也不能用,因为没window对象
            return [res, end - start]; // 返回数组,第一项是fib(44)的值,第二项是fib(44)递归计算用时
          },
          [this.fibNum] // 参数,从这里传递进去,数组形式
        )
        .then((res) => {
          console.log("then", res); // 另一个线程执行完以后就能拿到结果了
          this.fibRes = res[0];
          this.fibTime = res[1];
          this.btnLoading = false;
        })
        .catch((err) => {
          console.log("err", err);
          this.btnLoading = false;
        });
      /* 第二个UI操作 */
      let h2Dom = this.$refs.renderH2;
      let n = 0;
      let timer = setInterval(() => {
        if (n >= 60) {
          clearInterval(timer);
        } else {
          n++;
          h2Dom.innerHTML = n;
        }
      }, 100);
      // 使用web worker插件vue-work的确可以做到不阻塞
    },
    /**
     * 使用多个线程
     * */
    // 调用方式一 不传参
    noParamsFn() {
      this.loadingOne = true;
      console.time("多个线程计算用时1");
      this.worker2
        .postAll()
        .then((res) => {
          console.timeEnd("多个线程计算用时1");
          console.log("res", res); // 结果是一个数组 [267914296, 433494437, 701408733]
          this.loadingOne = false;
        })
        .catch((err) => {
          console.timeEnd("多个线程计算用时1");
          console.log("err", err);
          this.loadingOne = false;
        });
    },
    // 调用方式二 根据message的名字去指定谁(可多个)去执行 字符串形式
    byMessageNameStrFn() {
      this.loadingTwo = true;
      console.time("多个线程计算用时2");
      this.worker2
        .postAll(["fn1", "fn3"]) // 这里指定"fn1", "fn3"去执行
        .then((res) => {
          console.timeEnd("多个线程计算用时2");
          console.log("res", res); // 结果是一个数组 [267914296, 701408733]
          this.loadingTwo = false;
        })
        .catch((err) => {
          console.timeEnd("多个线程计算用时2");
          console.log("err", err);
          this.loadingTwo = false;
        });
    },
    // 调用方式三 根据message的名字去指定谁(可多个)去执行 对象形式
    byMessageNameObjParamsFn() {
      this.loadingThree = true;
      console.time("多个线程计算用时3");
      this.worker2
        .postAll([{ message: "fn1", args: ["代码修仙路漫漫", "加油干"] }]) // 这里指定"fn1" 去执行
        .then((res) => {
          console.timeEnd("多个线程计算用时3");
          console.log("res", res); // 结果是一个数组 []
          this.loadingThree = false;
        })
        .catch((err) => {
          console.timeEnd("多个线程计算用时3");
          console.log("err", err);
          this.loadingThree = false;
        });
    },
    /**
     * 使用Promise
     * */
    async usePromiseFn() {
      function asyncOne() {
        let async1 = new Promise(async (resolve, reject) => {
          function fib(n) {
            if ((n === 1) | (n === 2)) {
              return 1;
            } else {
              return fib(n - 1) + fib(n - 1);
            }
          }
          resolve(fib(30));
        });
        return async1;
      }

      function asyncTwo() {
        let async2 = new Promise(async (resolve, reject) => {
          function fib(n) {
            if ((n === 1) | (n === 2)) {
              return 1;
            } else {
              return fib(n - 1) + fib(n - 1);
            }
          }
          resolve(fib(30));
        });
        return async2;
      }

      function asyncThree() {
        let async3 = new Promise(async (resolve, reject) => {
          function fib(n) {
            if ((n === 1) | (n === 2)) {
              return 1;
            } else {
              return fib(n - 1) + fib(n - 1);
            }
          }
          resolve(fib(30));
        });
        return async3;
      }

      console.time("使用Promise搭配aysnc和await");

      // let paramsArr = [asyncOne()]; // 计算一个大概在3秒左右(计算一次刷新一次页面,精确一些)
      let paramsArr = [asyncOne(), asyncTwo(), asyncThree()]; // 计算三个耗时任务大概在9秒左右

      let res = await Promise.all(paramsArr);
      console.timeEnd("使用Promise搭配aysnc和await");
      console.log("结果", res);
    },
  },
  created() {
    // 1. 定义线程所用的消息函数数组
    const actions = [
      {
        message: "fn1", // message消息与func函数执行为映射关系
        func: (params1, params2) => {
          console.log("params参数-->", params1, params2);
          function fib(n) {
            if ((n == 1) | (n == 2)) {
              return 1;
            } else {
              return fib(n - 1) + fib(n - 2);
            }
          }
          return fib(30);
        },
      },
      {
        message: "fn2",
        func: () => {
          function fib(n) {
            if ((n == 1) | (n == 2)) {
              return 1;
            } else {
              return fib(n - 1) + fib(n - 2);
            }
          }
          return fib(30);
        },
      },
      {
        message: "fn3",
        func: () => {
          function fib(n) {
            if ((n == 1) | (n == 2)) {
              return 1;
            } else {
              return fib(n - 1) + fib(n - 2);
            }
          }
          // throw "一个报错挂了,其他的也跟着挂了,走.catch"; // 抛出错误(的确很像Promise.all())
          return fib(30);
        },
      },
    ];
    // 2. 根据消息函数数组去create创建一个worker,并存到data变量中去,以便于后续随时使用
    this.worker2 = this.$worker.create(actions);
  },
  // 别忘了在组件销毁前清除掉哦
  beforeDestroy() {
    this.worker = null;
  },
};
</script>

<style lang='less' scoped>
.bold {
  font-weight: 700;
  font-size: 24px;
}
.info {
  color: #999;
  font-size: 13px;
}
.UI {
  display: flex;
  align-items: center;
}
</style>

或者大家去笔者的GitHub仓库中拉取代码,跑起来看,更加方便理解。

GitHub仓库地址:https://github.com/shuirongshuifu/elementSrcCodeStudy

js中统计代码执行时长的三种方式

附带js中常用的统计程序执行时长的三种方式

// 计算时间方式一 
function fib(n) {
        if (n === 1 | n === 2) {
                return 1
        } else {
                return fib(n - 1) + fib(n - 2)
        }
}
let start = window.performance.now() // 单位毫秒
fib(40)
let end = window.performance.now() // 单位毫秒
console.log((end - start).toFixed(0) + '毫秒');
// 计算时间方式二 
function fib(n) {
        if (n === 1 | n === 2) {
                return 1
        } else {
                return fib(n - 1) + fib(n - 2)
        }
}
let start = Date.now() // 单位毫秒
fib(40)
let end = Date.now() // 单位毫秒
console.log((end - start).toFixed(0) + '毫秒');
console.time('tom')
console.timeEnd('tom')

A good memory is not as good as a bad pen, record it...

相关文章
|
28天前
|
Java 应用服务中间件 Apache
Maven程序 tomcat插件安装与web工程启动
Maven程序 tomcat插件安装与web工程启动
27 0
|
23天前
|
分布式计算 并行计算 安全
在Python Web开发中,Python的全局解释器锁(Global Interpreter Lock,简称GIL)是一个核心概念,它直接影响了Python程序在多线程环境下的执行效率和性能表现
【6月更文挑战第30天】Python的GIL是CPython中的全局锁,限制了多线程并行执行,尤其是在多核CPU上。GIL确保同一时间仅有一个线程执行Python字节码,导致CPU密集型任务时多线程无法充分利用多核,反而可能因上下文切换降低性能。然而,I/O密集型任务仍能受益于线程交替执行。为利用多核,开发者常选择多进程、异步IO或使用不受GIL限制的Python实现。在Web开发中,理解GIL对于优化并发性能至关重要。
42 0
|
4天前
|
存储 数据库 开发者
Flask中的蓝图与插件应用:构建模块化Web应用的利器
【7月更文挑战第19天】Flask蓝图和插件是构建模块化、可扩展和可维护Web应用的强大工具。蓝图允许你将应用分割成多个独立的部分,提高了代码的组织性和可重用性;而插件则为Flask应用提供了丰富的功能和社区支持,简化了开发过程。通过合理地使用蓝图和插件,你可以更加高效地开发出高质量的Web应用。
|
5天前
|
Python
Python线程是操作系统能够进行运算的最小单位
【7月更文挑战第18天】Python线程是操作系统能够进行运算的最小单位
9 1
|
9天前
|
安全 Java 开发者
Java并发编程中的线程安全性与性能优化
在Java编程中,处理并发问题是至关重要的。本文探讨了Java中线程安全性的概念及其在性能优化中的重要性。通过深入分析多线程环境下的共享资源访问问题,结合常见的并发控制手段和性能优化技巧,帮助开发者更好地理解和应对Java程序中的并发挑战。 【7月更文挑战第14天】
|
12天前
|
存储 安全 算法
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第72天】 在现代软件开发中,尤其是Java应用开发领域,并发编程是一个无法回避的重要话题。随着多核处理器的普及,合理利用并发机制对于提高软件性能、响应速度和资源利用率具有重要意义。本文旨在探讨Java并发编程的核心概念、线程安全的策略以及性能优化技巧,帮助开发者构建高效且可靠的并发应用。通过实例分析和理论阐述,我们将揭示在高并发环境下如何平衡线程安全与系统性能之间的关系,并提出一系列最佳实践方法。
|
18天前
|
监控 安全 Java
Java中的线程调度与性能优化技巧
Java中的线程调度与性能优化技巧
|
28天前
|
安全 算法 Java
Java并发编程中的线程安全与性能优化
在Java应用程序开发中,线程安全和性能优化是至关重要的方面。本文探讨了Java并发编程中常见的线程安全问题,并提供了实用的性能优化技巧。通过深入分析多线程环境下的共享资源访问、锁机制、并发集合等关键概念,帮助开发者有效提升程序的稳定性和执行效率。
47 15
|
19天前
|
缓存 JavaScript 前端开发
JavaScript进阶 - Web Workers与Service Worker
【7月更文挑战第4天】JavaScript的Web Workers和Service Worker增强了Web性能。Web Workers处理后台多线程,减轻主线程负担,但通信有开销,受同源策略限制。Service Worker则用于离线缓存和推送通知,需管理其生命周期、更新策略,并确保安全。两者都带来了挑战,但也极大提升了用户体验。通过理解和优化,开发者能构建更高效、安全的Web应用。
|
10天前
|
网络协议 安全 Python
我们将使用Python的内置库`http.server`来创建一个简单的Web服务器。虽然这个示例相对简单,但我们可以围绕它展开许多讨论,包括HTTP协议、网络编程、异常处理、多线程等。
我们将使用Python的内置库`http.server`来创建一个简单的Web服务器。虽然这个示例相对简单,但我们可以围绕它展开许多讨论,包括HTTP协议、网络编程、异常处理、多线程等。