Stories

Detail Return Return

虛擬線程:性能飛躍的底層秘密 - Stories Detail

一、引言

在當今高速發展的計算機領域,多線程編程已經成為了一種普遍的技術選擇。而虛擬線程作為多線程編程中的一個重要概念,正逐漸引起了人們的關注。虛擬線程不僅能夠提高程序的性能和響應能力,還能有效地利用計算機的資源。然而,虛擬線程的實現原理及其優缺點卻是一個備受關注的話題。本文將深入探討虛擬線程的實現原理,並分析其在實際應用中的優點和缺點。通過對虛擬線程的全面瞭解,我們將能夠更好地應用它來優化我們的程序,並在多線程編程中取得更好的效果。

二、背景

image.png

在傳統的Java線程模型中,每個線程都需要佔用操作系統的線程資源。線程的創建和銷燬都需要消耗一定的時間和系統資源,而線程的上下文切換也會帶來額外的開銷。當需要處理大量的併發任務時,線程的數量會急劇增加,從而導致系統資源的浪費和性能下降。
通過優化線程池配置,在IO密集型應用中,我們成功將應用的吞吐量從79提升到228,增長了188%。同時,接口的耗時也從650ms降低到231ms,降低了64.46%。儘管各個服務可能存在一些差異,但使用虛擬線程的方式顯著提升了應用的吞吐量,並降低了部分響應的耗時。

image.png

線程池通過複用已創建的線程,避免了頻繁創建和銷燬線程的開銷,並提高程序的性能和響應速度。但任務的IO操作和併發鎖導致線程等待或阻塞,產生上下文切換,從而導致CPU資源的浪費和應用性能下降。尤其是IO密集型服務:CPU與IO速度不匹配,造成CPU資源嚴重浪費。

image.png

三、虛擬線程介紹

虛擬線程是JDK中的一種輕量級線程,運行時僅是一個Java對象,與傳統的線程相比,在創建、銷燬和調度方面的開銷更小。

image.png

系統線程:操作系統調度的基本單位,由操作系統管理;
平台線程:Java虛擬機的線程,與操作系統一對一映射,受操作系統和硬件設備限制;
虛擬線程:一種輕量級線程【VirtualThread】 ;
載體線程:執行虛擬線程任務的平台線程。

3.1、使用
• 直接創建虛擬線程



Thread vt = Thread.startVirtualThread(() -> { System.out.println("hello wolrd virtual thread");});
• 通過虛擬線程的 ThreadFactory 創建虛擬線程





ThreadFactory tf = Thread.ofVirtual().factory();Thread vt = tf.newThread(() -> { System.out.println("hello wolrd virtual thread");});vt.start();
• 虛擬線程池


Executors.newVirtualThreadPerTaskExecutor();// 通過虛擬線程的ThreadFactory創建虛擬線程

3.2、狀態

image.png

3.3、原理

虛擬線程由executor、Continuation和state組成,其中Continuation是虛擬線程的核心,對task封裝,提供task等待或阻塞時出讓載體線程和task恢復運行時掛載到平台線程的功能。executor: 使用了 FIFO 模式的 ForkJoinPool 作為虛擬線程的調度器。

在虛擬線程中,任務執行時會調用Continuation的run()方法。該方法首先執行部分任務代碼,然後嘗試網絡IO。如果IO操作是阻塞的,會導致Continuation執行yield操作,讓出控制權。如果yield操作成功,虛擬線程會從載體線程中解綁(unmount),此時載體線程的棧數據會移動到Continuation的棧數據幀中,並保存在堆內存中。此時,虛擬線程的任務完成,但虛擬線程和Continuation並沒有終結和釋放,而是將載體線程釋放到執行器中,等待新的任務。如果yield操作失敗,説明無法獲取鎖,Continuation會對載體線程進行Park調用,將載體線程阻塞。此時,虛擬線程和載體線程都會被阻塞。

image.png

如上圖:6個任務被封裝到6個虛擬線程通過線程池[2個平台線程]執行,任務中有網絡IO:平台線程[thead-1]執行task1阻塞時,卸載task1後執行task3,執行task3也阻塞時執行task5。所有任務在等待網絡IO後,task1被掛載到平台線程[thead-2]上運行,直到任務結束。共享等待時間,6個任務完成耗時大大縮短。

需要注意的是,虛擬線程和Continuation的運行流程是由具體的實現機制決定的,上述描述是一種可能的情況,具體的實現可能會有所不同。此外,Continuation是一種用於實現輕量級線程的技術,它可以實現線程的暫停和恢復,從而提供更高效的併發執行能力。

3.4、優點

• 創建快:虛擬線程創建不需要創建系統線程,只需按照創建對象的流程初始化虛擬線程的屬性。應用能快速創建虛擬線程,且開銷小,使得應用程序可以創建大量的虛擬線程和有限的平台線程來處理高併發任務。
• 儘量不阻塞平台線程:當虛擬線程的任務阻塞或等待時,JVM快速將其從載體線程解除掛載,並調度其他虛擬線程掛載到該載體線程,無需上下文切換,大大提升CPU利用率。
• 等待時間少: 虛擬線程出讓平台,與其他等待狀態的虛擬線程共同等待,等待時間無疊加。
• 銷燬快:當任務完成後,JVM銷燬虛擬線程的堆棧、局部變量等,無需清理平台線程。

3.5、缺點

• 額外CPU消耗:虛擬線程被掛載時棧幀數據從堆區複製到平台線程的棧(載體線程),任務阻塞後虛擬線程卸載,從載體線程的棧數據幀複製到堆區。掛載和卸載過程中消耗CPU執行復制操作
• 侷限性:當任務調用本地方法、外部函數、synchronized塊或方法被阻塞時導致yield操作失敗,則虛擬線程阻塞在載體線程

3.6、測試

選取了業務中常見邏輯的接口:依賴四個外部數據,其中3個API,1個數據庫,通過線程池完成外部數據獲取,然後業務站點中處理數據並返回。

image.png

• 基於平台線程獲取外部數據 經多次調整線程池參數,獲取最優結果

image.png

• 基於虛擬線程獲取外部數據

image.png

通過優化線程池配置,在IO密集型應用中,我們成功將應用的吞吐量從79提升到228,增長了188%。同時,接口的耗時也從650ms降低到231ms,降低了64.46%。儘管各個服務可能存在一些差異,但使用虛擬線程的方式顯著提升了應用的吞吐量,並降低了部分響應的耗時。

四、總結

本文介紹了虛擬線程的概念、實現原理以及優缺點。虛擬線程是一種高效的輕量級線程技術,特別適用於IO密集型服務,可以顯著提升性能。我們的優化措施不僅僅關注吞吐量的增長,還注重降低接口耗時,以提供更快速、高效的應用體驗。

作者簡介

長栓,信也科技資深研發。

 

Add a new Comments

Some HTML is okay.