欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

[點晴永久免費OA]異步編程真的讓程序更快了嗎?

freeflydom
2024年3月28日 10:4 本文熱度 794

引言

現在異步編程真的是越來越普遍了,從前端的Promise到后端的Channel、Future、Task,異步編程正變得越來越流行。很多同學也玩得很溜了,滿世界的異步調用,讓程序的效率和用戶體驗都大大提升。不過,當談到為什么要使用異步編程,以及它背后的工作原理時,大部分同學就啞火了。對于一個有追求的程序員來說,我們不僅要會用,更要理解其中的原理,所謂“知其所以然”。

而且異步編程并不是銀彈,本質上它不會讓程序運行的更快,使用它也伴隨著復雜的錯誤處理和調試難題,比如著名的“回調地獄”。因此,了解它的工作原理,以及正確地使用它,對于編寫高質量的代碼來說特別重要。

本文,我們就來一起探討下同步和異步調用的本質區別,深入解析異步編程的工作原理,以及介紹如何在實際開發中靈活運用這兩種調用方式。

概念

要討論問題,首先得明確概念,也就是我們到底在說什么。

同步調用,簡單來說,就是執行多個任務的時候,其中一個任務必須完成后,才能開始下一個任務。在這種模式下,任務按照順序依次執行,每個任務的執行必須等待前一個任務完成,所以大家也稱之為阻塞調用。

在編程中,同步調用的一個典型應用場景是數據庫事務。比如,在事務中更新一系列的記錄時,系統會按照順序執行這些操作,直到全部完成,期間不會去處理其他任務。這確保了數據的一致性和完整性,但也意味著在事務處理期間,其他依賴于這些數據的操作必須等待。

異步調用,顧名思義,是一種任務可以在后臺執行,而不阻塞當前線程繼續執行其他任務的調用方式,這可以使多個任務得以并行處理。

在編程中,異步調用的一個典型應用場景是網絡請求。比如,前端向服務器請求數據時,我們可以不需要讓整個應用停下來等待服務器的響應。通過異步調用,前端可以在等待服務器響應的同時,繼續執行其他任務,比如響應用戶的輸入,這會提高用戶體驗。

簡單來說,同步調用就像是在排隊取餐,不能走開,而異步調用則像是掃碼點餐,可以去做其他事情,等飯好了給你送過來。

異步的優勢所在

更快

這里先拋出一個問題:異步會不會讓程序運行的更快?

我們以經典的網絡請求場景為例,當客戶端使用異步的方式發起一次請求后,程序霸占的當前線程就被底層系統分配去干別的事情去了,然后請求會在網絡上傳遞極短的一些時間,到達服務端后再進行一段時間的處理,最后再通過網絡將處理結果返回給客戶端底層系統,底層系統再喚起之前的任務繼續處理。

在這個過程中,網絡來回傳輸的時間、服務端處理的時間都沒有受到異步調用的任何影響,反而可能會因為異步調用產生任務切換而增加網絡請求的響應時間。所以單次的異步調用并沒有讓程序運行的更快。

但是但是,異步調用還是可能會讓程序整體運行的更快。還是以網絡請求場景為例,假設我們需要在頁面上發起3個網絡請求,每個網絡請求的響應時間都是基本相同的,同步的情況下我們只能一個一個的干,總的響應時間就是單次網絡請求響應時間的3倍,如果換成異步調用,理想情況下,這三個網絡請求可以在服務端并行處理,而網絡傳輸的時間是極短的,那么總的響應時間可能就是一個比單次網絡請求響應時間略高一點的數字。所以異步調用相比同步調用,很有可能會讓程序整體運行的更快。

談到更快時,我們這里一直比較的就是時間,如果網絡傳輸的時間、服務端處理的時間都很短,短到就像本地的一次函數調用,那么異步也不會讓程序更快。所以根本的問題是網絡傳輸的時間太慢、服務端處理的時間太慢,它們相比CPU的處理速度要慢上很多個數量級,所以這才讓異步有了可乘之機,而異步就是在這些網絡IO、磁盤IO等慢速設備的通信上發揮主要作用。

更多

我們以一個服務端網絡處理程序為例,當請求到達服務端時,程序會給這個請求分配一個線程,用來運行相關的服務端處理程序,假設這個處理中還要調用別的API,同步調用和異步調用就會出現不同的行為了。

同步調用時,線程會一直等在這里,等待的時候誰也不能搶走這個線程,直到這次內部調用返回結果,然后繼續處理,直到全部完成,最后返回給調用方。

異步調用時,調用發起后,線程就被底層系統分配給別的任務了,比如用來接收新的網絡請求,等這次內部調用的結果返回后,底層系統再為本次任務分配線程資源,然后繼續處理,直到全部完成,最后返回給調用方。

我們可以看到,在使用異步調用的情況下,線程的利用率提高了,而這會節省大量的服務器資源。比如,在Linux系統中,一個線程會占用8M的內存資源,那么同步調用時,8G的內存也就能同時接入大概1000個請求,改為異步調用后,8G的內存能同時接入多少請求呢?這里做一個不是很嚴謹的計算,假設1個請求的完整處理時間為100毫秒,請求接入到發起異步調用的時間為1毫秒,那么使用異步調用后,8G內存就能在這100毫秒內接收100倍的請求,也就是10萬個請求。

這也是Go語言、Node.js等可以輕松駕馭高并發的核心法門。

更省

有一種說法是異步調用后,CPU就去干別的了,不用等著網絡請求返回,所以節省了CPU資源。其實現代操作系統一般沒有這么傻,它有一套比較科學的CPU調度算法,CPU并不會傻傻的等著網絡請求返回,除非我們使用特殊的方法霸占著CPU不放。這種說法可能只在古老的操作系統或者一些特殊的嵌入式系統中存在。

異步節省內存資源是實實在在的,同樣的網絡請求數量下,需要的線程更少了,占用的內存也就更少了。

更好的用戶體驗

我們可以以一個現代Web應用的實例來說明。當用戶在一個復雜的Web應用中進行操作時,比如提交一個表單,這個表單的數據需要通過網絡發送到服務器。在這個過程中,我們不希望用戶界面凍結或變得無響應。通過使用異步調用發送數據,用戶界面可以繼續響應其他用戶操作,比如滾動頁面、點擊其他按鈕等。服務器的響應會在數據處理完成后返回,這時應用會相應地更新用戶界面,而用戶可能都沒有注意到這個后臺的數據交換過程。

異步的實現原理

接下來,我們深入探討一下異步是怎么做到上邊這一切的,特別是事件循環、回調函數,以及Promises和Async/Await這些概念。以Node.js為例,可以先看看這張圖,下邊會有詳細介紹。

事件循環

在一家餐廳里,有一個廚師(CPU)和一個服務員(事件循環)。當顧客(任務)下單(發起異步調用)后,服務員記錄下訂單,然后繼續服務其他顧客。廚師在后廚準備好食物后,服務員再將食物遞給對應的顧客。這個過程中,服務員不斷的在顧客和廚師之間循環,確保每個顧客的需求都得到滿足,這就是事件循環的機制。

在不同的操作系統和語言框架中,事件循環的具體實現可能有所不同,但核心思想是一致的:使得單線程環境下,可以高效地處理多個異步任務,而不會造成阻塞。

Node.js

Node.js是一個基于Chrome V8引擎的JavaScript運行環境,它使用事件驅動、非阻塞IO模型,非常適合處理大量的并發連接。Node.js的事件循環由libuv庫實現,這個庫專門為了提高Node.js的異步IO性能而設計。

在Node.js中,事件循環負責執行用戶代碼、收集和處理事件,以及執行隊列中的子任務。

.NET

在.NET框架中,異步編程模型(Asynchronous Programming Model, APM)和基于任務的異步模式(Task-based Asynchronous Pattern, TAP)都是.NET中處理異步操作的方式。.NET中的事件循環不像Node.js那樣明顯,因為.NET應用通常運行在多線程環境下,通過線程池(Thread Pool)來處理異步任務。

在.NET中,異步操作通常通過Task來表示,搭配使用async和await關鍵字讓異步代碼的編寫和閱讀更加直觀。.NET運行時會負責調度這些Task到線程池中的線程上執行,從而實現非阻塞的異步操作。

操作系統

語言框架的異步處理都是基于操作系統的底層支持。

在操作系統層面,Linux和Windows提供了不同的機制來實現高效的IO事件處理。

  • Linux上的epoll是一種高效的IO事件通知機制,它允許應用程序監視多個文件描述符,以了解是否有IO操作可執行。epoll相比于傳統的select或poll,在處理大量并發連接時可以顯著減少資源消耗和提高性能。

  • Windows上的IO完成端口(IOCP)是一個高效的線程池技術,用于處理大量的并發IO操作。IOCP能夠將IO操作的完成通知直接與線程池結合起來,當IO操作完成時,相應的處理線程會被喚醒來處理結果。

語言框架為了實現異步操作,在不同的操作系統上會選擇相應的異步IO處理方式。

回調函數

回調函數就像是你對服務員說:“當我的漢堡準備好了,請通知我。”服務員(事件循環)記下了這個請求,當廚師(CPU)做好漢堡后,服務員會回來通知你。這個過程就是回調機制。

然而,如果你的要求變得復雜,比如:“我的漢堡準備好后,請通知我,然后我會要求加薯條,薯條準備好后,請再通知我,我可能還會有其他要求……”這樣的多層次回調會導致所謂的“回調地獄”,使得代碼難以閱讀和維護。

function prepareBurger(callback) {
  console.log("開始準備漢堡...");
  setTimeout(() => {
    console.log("漢堡準備好了!");
    callback("漢堡");
  }, 2000); // 假設準備漢堡需要2秒鐘
}
function prepareFries(callback) {
  console.log("開始準備薯條...");
  setTimeout(() => {
    console.log("薯條準備好了!");
    callback("薯條");
  }, 1500); // 假設準備薯條需要1.5秒鐘
}
// 請求漢堡,然后請求薯條
prepareBurger(function(burger) {
  console.log("你的" + burger + "已經準備好了。");
  // 漢堡準備好后,請求薯條
  prepareFries(function(fries) {
    console.log("你的" + fries + "也準備好了。");
    // 如果這里還有更多的異步請求,代碼會繼續嵌套下去...
  });
});

Promises和Async/Await

為了解決“回調地獄”的問題,現代編程語言引入了Promises和Async/Await,以Javascript為例:

Promises 就像是你給服務員下了一個訂單,并得到了一個“承諾”。服務員說:“我保證會告訴你何時你的漢堡準備好。”這樣,你就不需要在柜臺前等待,而是可以去做其他事情,服務員會在承諾的時間里來通知你。

function prepareBurger() {
  // 返回一個Promise對象
  return new Promise((resolve, reject) => {
    console.log("開始準備漢堡...");
    setTimeout(() => {
      // 模擬漢堡準備過程
      console.log("漢堡準備好了!");
      resolve("漢堡"); // 成功完成時調用resolve
    }, 2000); // 假設準備漢堡需要2秒鐘
  });
}
// 調用prepareBurger,并處理結果
prepareBurger().then(burger => {
  console.log("你的" + burger + "已經準備好了。");
}).catch(error => {
  console.log("出錯了:" + error);
});

Promise的寫法看起來還是有點怪異,Async/Await 則是在Promises的基礎上,讓異步代碼看起來更像同步代碼。使用async/await時,你可以用同步的方式寫異步代碼,這讓代碼更加直觀易懂。比如,你對服務員說:“我會在這里等,你準備好漢堡后直接給我。”盡管實際上漢堡的準備是異步的,但對你來說,就像是同步等待結果一樣。

async function getOrder() {
  try {
    // 等待prepareBurger完成,并獲取結果
    const burger = await prepareBurger();
    console.log("你的" + burger + "已經準備好了。");
  } catch (error) {
    // 處理可能發生的錯誤
    console.log("出錯了:" + error);
  }
}
// 調用getOrder
getOrder();

async/await 其實還利用了協程的一些處理方式,協程不是操作系統提供的,而是由編程語言框架在用戶程序中實現的,在異步編程中,它就是用來在IO操作發起后,將線程分給其它的任務,在IO操作完成后再給任務分配線程。具體到JavaScript中,是通過Generator生成器實現的,它可以控制函數的暫停和恢復,async/await只是做了一個包裝,實際執行時,運行引擎會轉換處理。

在 .NET 平臺中,同樣支持使用 async/await 的方式編寫異步代碼,只不過 Promise 變成了 Task。

總結

最后,讓我們總結一下同步調用和異步調用的區別,以及它們對軟件開發的影響。

首先,同步調用就像是在餐廳里排隊取餐,你得等服務員把飯端上來后才能干別的事情;而異步調用則像是掃碼點餐,餐點制作的時候,你可以去做任何其他事情。簡而言之,同步調用會阻塞當前操作直到任務完成,而異步調用不會,它允許程序在等待過程中繼續執行其他任務。

對軟件開發來說,這兩種調用方式的本質區別影響深遠。同步調用因為簡單直接,適合那些必須順序執行、步步為營的任務,特別是計算密集型的任務,異步了也沒有可以節省的地方;但是,在處理IO操作等耗時任務時,同步調用可能會導致程序"卡住",既霸占大量的資源,又影響用戶體驗,此時選擇異步調用則能更有效的利用計算資源,且顯著提高程序的響應性和性能,尤其是在需要大量IO操作的場景下,比如網絡服務器、大型數據庫操作等。


轉自博客園,作者螢火架構https://www.cnblogs.com/bossma/p/18065866


該文章在 2024/3/28 16:34:59 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved