成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Puppeteer性能優(yōu)化與執(zhí)行速度提升

KnewOne / 3050人閱讀

摘要:所以需要理解運(yùn)行的原理,才能方便優(yōu)化。如果啟動(dòng)時(shí)能綁定到某個(gè)核上也能提升速度單核上進(jìn)行進(jìn)程切換耗費(fèi)的時(shí)間更少。優(yōu)化執(zhí)行流程接下來我們再多帶帶優(yōu)化對應(yīng)的頁面。參考文章性能優(yōu)化與執(zhí)行速度提升利用優(yōu)化

Puppeteer自身不會消耗太多資源,耗費(fèi)資源的大戶是Chromium Headless。所以需要理解Chromium運(yùn)行的原理,才能方便優(yōu)化。

Chromium消耗最多的資源是CPU,一是渲染需要大量計(jì)算,二是Dom的解析與渲染在不同的進(jìn)程,進(jìn)程間切換會給CPU造成壓力(進(jìn)程多了之后特別明顯)。其次消耗最多的是內(nèi)存,Chromium是以多進(jìn)程的方式運(yùn)行,一個(gè)頁面會生成一個(gè)進(jìn)程,一個(gè)進(jìn)程占用30M左右的內(nèi)存,大致估算1000個(gè)請求占用30G內(nèi)存,在并發(fā)高的時(shí)候內(nèi)存瓶頸最先顯現(xiàn)。

優(yōu)化最終會落在內(nèi)存和CPU上(所有軟件的優(yōu)化最終都要落到這里),通常來說因?yàn)椴l(fā)造成的瓶頸需要優(yōu)化內(nèi)存,計(jì)算速度慢的問題要優(yōu)化CPU。使用Puppeteer的用戶多半會更關(guān)心計(jì)算速度,所以下面我們談?wù)勅绾蝺?yōu)化Puppeteer的計(jì)算速度。

優(yōu)化Chromium啟動(dòng)項(xiàng)

通過查看Chromium啟動(dòng)時(shí)都有哪些參數(shù)可以配置,能找到大部分線索,因?yàn)镃hromium這種頂級的開源產(chǎn)品,文檔與接口都是非常清晰的,肯定可以找到相關(guān)配置項(xiàng)來定制啟動(dòng)方式。Chromium 啟動(dòng)參數(shù)列表

我們需要找到下面幾種配置來提升速度:

    如果將Dom解析和渲染放到同一進(jìn)程,肯定能提升時(shí)間(進(jìn)程上下文切換的時(shí)間)。對應(yīng)的配置是??single-process?

    部分功能disable掉,比如GPU、Sandbox、插件等,減少內(nèi)存的使用和相關(guān)計(jì)算。

    如果啟動(dòng)Chromium時(shí)能綁定到某個(gè)CPU核上也能提升速度(單核上進(jìn)行進(jìn)程切換耗費(fèi)的時(shí)間更少)??上]有找到對應(yīng)的配置,官方文檔寫的是Chromium啟動(dòng)時(shí)會自動(dòng)綁定CPU大核(ARM架構(gòu)的CPU通常有大小核之分),依此推測Chromium啟動(dòng)時(shí)是會綁核的。(此處我并未驗(yàn)證)

最后配置如下:

const browser = await puppeteer.launch(
{
    headless:true,
    args: [
        ‘–disable-gpu’,
        ‘–disable-dev-shm-usage’,
        ‘–disable-setuid-sandbox’,
        ‘–no-first-run’,
        ‘–no-sandbox’,
        ‘–no-zygote’,
        ‘–single-process’
    ]
});

Chromium 啟動(dòng)參數(shù)列表?文檔中的配置項(xiàng)都可以嘗試看看,我沒有對所有選項(xiàng)做測試,但可以肯定存在某些選項(xiàng)能提升Chromium速度。

優(yōu)化Chromium執(zhí)行流程

接下來我們再多帶帶優(yōu)化Chromium對應(yīng)的頁面。我之前的文章中提過,如果每次請求都啟動(dòng)Chromium,再打開tab頁,請求結(jié)束后再關(guān)閉tab頁與瀏覽器。流程大致如下:

請求到達(dá)->啟動(dòng)Chromium->打開tab頁->運(yùn)行代碼->關(guān)閉tab頁->關(guān)閉Chromium->返回?cái)?shù)據(jù)

真正運(yùn)行代碼的只是tab頁面,理論上啟動(dòng)一個(gè)Chromium程序能運(yùn)行成千上萬的tab頁,可不可以復(fù)用Chromium每次只打開一個(gè)tab頁然后關(guān)閉呢?當(dāng)然是可以的,Puppeteer提供了?puppeteer.connect()??方法,可以連接到當(dāng)前打開的瀏覽器。流程如下:

請求到達(dá)->連接Chromium->打開tab頁->運(yùn)行代碼->關(guān)閉tab頁->返回?cái)?shù)據(jù)

代碼如下:

const MAX_WSE = 4;  //啟動(dòng)幾個(gè)瀏覽器 
let WSE_LIST = []; //存儲browserWSEndpoint列表
init();
app.get("/", function (req, res) {
    let tmp = Math.floor(Math.random()* MAX_WSE);
    (async () => {
        let browserWSEndpoint = WSE_LIST[tmp];
        const browser = await puppeteer.connect({browserWSEndpoint});
        const page = await browser.newPage();
        await page.goto("file://code/screen/index.html");
        await page.setViewport({
            width: 600,
            height: 400
        });                
        await page.screenshot({path: "example.png"});
        await page.close();
        res.send("Hello World!");
    })();
});

function init(){
    (async () => {
        for(var i=0;itrue,
                args: [
                "--disable-gpu",
                "--disable-dev-shm-usage",
                "--disable-setuid-sandbox",
                "--no-first-run",
                "--no-sandbox",
                "--no-zygote",
                "--single-process"
            ]});
            browserWSEndpoint = await browser.wsEndpoint();
            WSE_LIST[i] = browserWSEndpoint;
        }
        console.log(WSE_LIST);
    })();        
}
利用cluster優(yōu)化Puppeteer

通常情況下我們會使用??.map()??搭配??Promise.all()??的方式并行處理異步,但是在使用?Puppeteer?批量截圖時(shí)發(fā)現(xiàn)?Promise.all?會打開多個(gè)瀏覽器,導(dǎo)致機(jī)器性能急劇下降。

?Promise.all()??并行處理

利用??Reduce??是多個(gè)?Promise?順序執(zhí)行

await tasks.reduce((sequence, url, idx) => {
  return sequence.then(() => {
    // doAnalyze 是個(gè)異步函數(shù)
    return doAnalyze(url, idx);
  });
}, Promise.resolve())

場景:有40個(gè)URL,需要獲取每個(gè)博客的首頁截圖

如果是?Promise.all()?,程序啟動(dòng)會同時(shí)打開20+的chromium瀏覽器,導(dǎo)致機(jī)器卡死。

使用?reduce?緩解了壓力,但沒充分利用多核性能

參入?Cluster?

// cluster_index.js 入口文件
const cluster = require("cluster");

(async () => {
  let run;
  if (cluster.isMaster) {
    run = require("./cluster_master");
  } else {
    run = require("./cluster_worker");
  }
  try {
    await run();
  } catch (e) {
    // 追蹤函數(shù)的調(diào)用軌跡
    console.trace(e);
  }
})();
// cluster_master.js master進(jìn)程分配任務(wù)

const cluster = require("cluster");
const numCPUs = require("os").cpus().length;

// 處理的任務(wù)列表
let arr = [
  "https://github.com/guoguoya",
  "http://www.52cik.com",
  "http://zhalice.com",
  "https://www.yzqroom.cn",
  "http://zxh.name",
  "https://fogdong.github.io/",
  "http://github.com/elsieyin",
  "https://summer.tlb058.com",
  "https://skymon4.cn",
  "http://www.jiweiqing.cn",
  "http://effect.im",
  "http://dingkewz.com",
  "http://xcdh.me",
  "http://d2g.io",
  "http://codingdemon.com",
  "http://blog.leanote.com/dujuncheng",
  "http://niexiaotao.com",
  "http://zhengchengwen.com",
  "http://blog.tophefei.com",
  "https://zh-rocco.github.io",
  "http://wangyn.net",
  "http://dscdtc.ml",
  "http://jweboy.github.io",
  "http://www.wenghaoping.com",
  "http://zhoujingchao.github.io",
  "http://kyriejoshua.github.io/jo.github.io/",
  "http://www.withyoufriends.com",
  "http://if2er.com",
  "https://github.com/zhou-yg",
  "http://github/suoutsky",
  "http://richardsleet.github.io",
  "http://www.89io.com",
  "https://guoshencheng.com",
  "http://www.landluck.com.cn",
  "http://www.89io.com",
  "http://myoungxue.top",
  "https://github.com/Wangszzju",
  "http://www.hacke2.cn",
  "https://github.com/enochjs",
  "https://i.jakeyu.top",
  "http://muyunyun.cn",
];

module.exports = async () => {
  // 每個(gè) CPU 分配 N 個(gè)任務(wù)
  const n = Math.floor(arr.length / numCPUs);
  // 未分配的余數(shù)
  const remainder = arr.length % numCPUs;

  for (let i = 1; i <= numCPUs; i += 1) {
    const tasks = arr.splice(0, n + (i > remainder ");"exit", (worker) => {
    console.log(`worker #${worker.id} PID:${worker.process.pid} died`);
  });
  cluster.on("error", (err) => {
    console.log(`worker #${worker.id} PID ERROR: `, err);
  });
};
// cluster_worker.js worker進(jìn)程 完成任務(wù)

const cluster = require("cluster");
const puppeteer = require("puppeteer");

// 禁止直接啟動(dòng)
if (cluster.isMaster) {
  console.log("----", cluster.worker.id)
  process.exit(0);
}

module.exports = async () => {
  const env = process.env.tasks;
  let tasks = [];
  if (/^[.*]$/.test(env)) {
    tasks = JSON.parse(env);
  }
  if (tasks.length === 0) {
    console.log("");, tasks)
    // 非法啟動(dòng), 釋放進(jìn)程資源
    process.exit(0);
  }
  console.log(`worker #${cluster.worker.id} PID:${process.pid} Start`);
  await tasks.reduce((sequence, url, idx) => {
    return sequence.then(() => {
      return doAnalyze(url, idx);
    });
  }, Promise.resolve())

  console.log(cluster.worker.id + " 順利完成");
  process.exit(0);
};

async function doAnalyze(url, i) {
  try {
    const browser = await (puppeteer.launch({
      // 若是手動(dòng)下載的chromium需要指定chromium地址, 默認(rèn)引用地址為 /項(xiàng)目目錄/node_modules/puppeteer/.local-chromium/
      // executablePath: "/Users/huqiyang/Documents/project/z/chromium/Chromium.app/Contents/MacOS/Chromium",
      //設(shè)置超時(shí)時(shí)間
      timeout: 30000,
      //如果是訪問https頁面 此屬性會忽略https錯(cuò)誤
      ignoreHTTPSErrors: true,
      // 打開開發(fā)者工具, 當(dāng)此值為true時(shí), headless總為false
      devtools: false,
      // 關(guān)閉headless模式, 會打開瀏覽器
      headless: false
    }));
    const page = await browser.newPage();
    await page.setViewport({width: 1920, height: 1080});
    await page.goto(url);
    await page.waitFor(4000);
    console.log(cluster.worker.id, url, i, "截圖中...");
    await page.screenshot({
      path: `./img_cluster/${cluster.worker.id}-${i}.png`,
      // path: "3.png",
      type: "png",
      // quality: 100, 只對jpg有效
      // fullPage: true,
      // 指定區(qū)域截圖,clip和fullPage兩者只能設(shè)置一個(gè)
      // clip: {
      //   x: 0,
      //   y: 0,
      //   width: 1920,
      //   height: 600
      // }
    });
    browser.close();
  } catch (error) {
    console.log(cluster.worker.id, url, i)
    console.log(error)
  }
};
多個(gè)page輪詢與多個(gè)browser輪詢

為了性能,現(xiàn)有解決方案是初始化若干個(gè)browser,請求打過來時(shí),直接在browserList中取一個(gè)browser實(shí)例使用。 作為對比,可以參考初始化一個(gè)browser,預(yù)先打開若干個(gè)page,請求打過來時(shí),直接在pageList中取一個(gè)page實(shí)例使用。

參考文章:

Puppeteer性能優(yōu)化與執(zhí)行速度提升 利用cluster優(yōu)化Puppeteer

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/7302.html

相關(guān)文章

  • 前端每周清單第 29 期:Web 現(xiàn)狀分析優(yōu)化策略、Vue 單元測試、Headless Chrom

    摘要:前端每周清單第期現(xiàn)狀分析與優(yōu)化策略單元測試爬蟲作者王下邀月熊編輯徐川前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實(shí)踐深度閱讀開源項(xiàng)目巔峰人生等欄目。 showImg(https://segmentfault.com/img/remote/1460000011008022); 前端每周清單第 29 期:Web 現(xiàn)狀分析與優(yōu)化策略...

    HackerShell 評論0 收藏0
  • 從零開始開發(fā)一個(gè)Node交互式命令行應(yīng)用

    摘要:導(dǎo)言對于大多數(shù)前端開發(fā)者而言,談到命令行工具,大家肯定都用過。但是談到開發(fā)命令行工具,估計(jì)就沒幾人有了解了。如何優(yōu)化這個(gè)圖片爬蟲工具目前還有點(diǎn)啊,我們的目標(biāo)是要開發(fā)一個(gè)交互式的命令行應(yīng)用,肯定不能止于此。 導(dǎo)言:對于大多數(shù)前端開發(fā)者而言,談到命令行工具,大家肯定都用過。但是談到開發(fā)命令行工具,估計(jì)就沒幾人有了解了。本文旨在用最短的時(shí)間內(nèi),幫您開發(fā)一個(gè)實(shí)用(斜眼笑)的圖片爬蟲命令行應(yīng)用。...

    Harriet666 評論0 收藏0
  • 前端每周清單第 48 期:Slack Webpack 構(gòu)建優(yōu)化,CSS 命名規(guī)范用戶追蹤,Vue.

    摘要:發(fā)布是由團(tuán)隊(duì)開源的,操作接口庫,已成為事實(shí)上的瀏覽器操作標(biāo)準(zhǔn)。本周正式發(fā)布,為我們帶來了,,支持自定義頭部與腳部,支持增強(qiáng),兼容原生協(xié)議等特性變化。新特性介紹日前發(fā)布了大版本更新,引入了一系列的新特性與提升,本文即是對這些變化進(jìn)行深入解讀。 showImg(https://segmentfault.com/img/remote/1460000012940044); 前端每周清單專注前端...

    sean 評論0 收藏0
  • 前端每周清單年度總結(jié)盤點(diǎn)

    摘要:前端每周清單年度總結(jié)與盤點(diǎn)在過去的八個(gè)月中,我?guī)缀踔蛔隽藘杉?,工作與整理前端每周清單。本文末尾我會附上清單線索來源與目前共期清單的地址,感謝每一位閱讀鼓勵(lì)過的朋友,希望你們能夠繼續(xù)支持未來的每周清單。 showImg(https://segmentfault.com/img/remote/1460000010890043); 前端每周清單年度總結(jié)與盤點(diǎn) 在過去的八個(gè)月中,我?guī)缀踔蛔隽?..

    jackwang 評論0 收藏0
  • 前端核心工具:yarn、npm、cnpm三者如何優(yōu)雅的在一起使用 ?

    摘要:由于文件中版本號的特點(diǎn),下面三個(gè)版本號在安裝的時(shí)候代表不同的含義。安裝版本統(tǒng)一為了防止拉取到不同的版本,有一個(gè)鎖定文件記錄了被確切安裝上的模塊的版本號。 showImg(https://segmentfault.com/img/bVbs8Rg?w=1920&h=1080); 一位用不好包管理器的前端,是一個(gè)入門級前端,一個(gè)用不好webpack的前端,是一個(gè)初級前端 三個(gè)包管理器是可以一...

    sihai 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<