日本电影一区二区_日本va欧美va精品发布_日本黄h兄妹h动漫一区二区三区_日本欧美黄色

Java 和低延遲(java延時(shí)任務(wù))

可以構(gòu)建在對(duì)外部事件的響應(yīng)時(shí)間方面滿足非常嚴(yán)格的要求的 Java 應(yīng)用程序,但這確實(shí)需要仔細(xì)考慮。本文討論了在 Java 中開(kāi)發(fā)低延遲代碼時(shí)需要考慮的事項(xiàng)。

每日分享最新,最流行的軟件開(kāi)發(fā)知識(shí)與最新行業(yè)趨勢(shì),希望大家能夠一鍵三連,多多支持,跪求關(guān)注,點(diǎn)贊,留言。

Java 和低延遲(java延時(shí)任務(wù))

我已經(jīng)記不清有多少次我被告知 Java 不是一種適合用于開(kāi)發(fā)以性能為主要考慮因素的應(yīng)用程序的語(yǔ)言。我的第一反應(yīng)通常是要求澄清“性能”作為兩個(gè)最常見(jiàn)的衡量標(biāo)準(zhǔn)的實(shí)際含義 – 吞吐量和延遲,有時(shí)會(huì)相互沖突,并且針對(duì)其中一個(gè)進(jìn)行優(yōu)化的方法可能會(huì)對(duì)另一個(gè)產(chǎn)生不利影響.

存在用于開(kāi)發(fā) Java 應(yīng)用程序的技術(shù),這些技術(shù)可以匹配甚至超過(guò)使用更傳統(tǒng)的用于此目的的語(yǔ)言構(gòu)建的應(yīng)用程序的性能要求。但是,從延遲的角度來(lái)看,即使這樣也可能不足以獲得最佳性能。Java 應(yīng)用程序仍然必須依賴操作系統(tǒng)來(lái)提供對(duì)底層硬件的訪問(wèn)。通常,延遲敏感(通常稱為“實(shí)時(shí)”)應(yīng)用程序在幾乎可以直接訪問(wèn)底層硬件時(shí)運(yùn)行得最好,這同樣適用于 Java。在本文中,我們將介紹一些當(dāng)我們希望我們的應(yīng)用程序最有效地利用系統(tǒng)資源時(shí)可以采取的方法。

Java 從一開(kāi)始就被設(shè)計(jì)為在廣泛的硬件和系統(tǒng)架構(gòu)中以二進(jìn)制級(jí)別可移植。這是通過(guò)設(shè)計(jì)和實(shí)現(xiàn)虛擬機(jī)(執(zhí)行平臺(tái)的抽象模型)并讓它執(zhí)行Java 源編譯器的輸出來(lái)完成的。爭(zhēng)論的焦點(diǎn)是遷移到不同類型的硬件平臺(tái)只需要移植虛擬機(jī)。應(yīng)用程序和庫(kù)無(wú)需修改即可運(yùn)行(“一次編寫(xiě),到處運(yùn)行”的口號(hào))。

但是,具有嚴(yán)格延遲和性能要求的應(yīng)用程序通常需要在執(zhí)行時(shí)盡可能接近硬件 – 他們希望從硬件中榨取所有可能的性能,并且不想要純粹為了可移植性或像動(dòng)態(tài)內(nèi)存管理這樣的抽象編程概念阻礙了。

多年來(lái),Java 虛擬機(jī)已經(jīng)發(fā)展成為一個(gè)極其復(fù)雜的執(zhí)行平臺(tái),可以在運(yùn)行時(shí)從 Java 字節(jié)碼生成機(jī)器代碼,并根據(jù)動(dòng)態(tài)收集的指標(biāo)優(yōu)化該代碼。這是靜態(tài)編譯語(yǔ)言(如 C )無(wú)法做到的,因?yàn)樗鼈儧](méi)有所需的運(yùn)行時(shí)信息。選擇數(shù)據(jù)結(jié)構(gòu)和算法時(shí)的謹(jǐn)慎方法可以最大限度地減少甚至消除垃圾收集的需要——這可能是 Java 運(yùn)行時(shí)環(huán)境中最明顯的一個(gè)方面,它阻止了一致的延遲時(shí)間。

但歸根結(jié)底,Java 虛擬機(jī)只是——虛擬的——它需要在操作系統(tǒng)之上運(yùn)行以管理其對(duì)硬件平臺(tái)的訪問(wèn)。無(wú)論該操作系統(tǒng)是 Linux(可能是服務(wù)器端環(huán)境中使用最廣泛的)、Windows 還是其他操作系統(tǒng),問(wèn)題仍然存在。

Linux 的“問(wèn)題”

Linux作為 Unix 操作系統(tǒng)家族的一員,多年來(lái)一直在發(fā)展。Unix 的第一個(gè)版本是在 1960 年代后期開(kāi)發(fā)的。它首先在學(xué)術(shù)界和研究界發(fā)展壯大并獲得了極大的知名度,然后在商業(yè)界以各種形式出現(xiàn)。Linux 已成為 Unix 的主要變體——盡管它仍然保留了許多原始特性。如今,隨著基于容器的執(zhí)行環(huán)境和云的出現(xiàn),它的主導(dǎo)地位幾乎已經(jīng)完全。

但是,從實(shí)時(shí)或延遲敏感型應(yīng)用程序的角度來(lái)看,Linux/Unix 確實(shí)存在問(wèn)題。這些主要源于 Unix 被設(shè)計(jì)為分時(shí)系統(tǒng)這一基本事實(shí)。它最初的硬件平臺(tái)是微型計(jì)算機(jī),同時(shí)被許多不同的用戶共享。所有用戶都有自己的工作要做,而 Unix 竭盡全力確保所有人都能“公平地分享”計(jì)算機(jī)資源。

實(shí)際上,操作系統(tǒng)會(huì)偏愛(ài)執(zhí)行大量 I/O 的用戶——包括在終端與系統(tǒng)交互——以犧牲主要執(zhí)行計(jì)算的任務(wù)(所謂的 CPU 密集型作業(yè))為代價(jià)。當(dāng)我們考慮到當(dāng)時(shí)的計(jì)算機(jī)幾乎都是單 CPU(單核)時(shí),這是有道理的。

然而,隨著多 CPU 計(jì)算機(jī)的發(fā)展,需要對(duì) Unix 操作系統(tǒng)的核心進(jìn)行一些認(rèn)真的重新設(shè)計(jì),以允許有效地使用這些執(zhí)行內(nèi)核。但同樣的方法仍然適用,交互式任務(wù)總是比 CPU 密集型任務(wù)更受歡迎。有了多個(gè)內(nèi)核可用,最終效果仍然是提高整體性能。

如今,幾乎每臺(tái)計(jì)算機(jī)都將擁有多個(gè)內(nèi)核,從手機(jī)等移動(dòng)設(shè)備到工作站,再到服務(wù)器級(jí)機(jī)器。檢查這些環(huán)境并查看我們是否可以采取不同的方法來(lái)改進(jìn)平臺(tái)以更有效地支持實(shí)時(shí)、延遲敏感的應(yīng)用程序似乎是有效的。

我們?nèi)绾谓鉀Q這些問(wèn)題?

在我工作的 Chronicle Software,我們已經(jīng)開(kāi)發(fā)了許多開(kāi)源庫(kù)來(lái)支持構(gòu)建針對(duì)低延遲進(jìn)行優(yōu)化的應(yīng)用程序,這是基于該領(lǐng)域多年的經(jīng)驗(yàn)。本文的其余部分描述了我們學(xué)到的一些幫助我們實(shí)現(xiàn)這一目標(biāo)的東西。

Java 運(yùn)行時(shí)

影響 Java 應(yīng)用程序延遲的主要問(wèn)題是那些與垃圾收集堆管理和使用鎖同步訪問(wèn)共享資源有關(guān)的問(wèn)題。存在解決這兩個(gè)問(wèn)題的技術(shù),盡管它們確實(shí)需要開(kāi)發(fā)人員在一定程度上偏離慣用的 Java 編程風(fēng)格。理想情況下,我們會(huì)使用封裝較低級(jí)別細(xì)節(jié)和專門(mén)技術(shù)的庫(kù),但我們確實(shí)需要了解“幕后”正在發(fā)生的事情。

為低延遲應(yīng)用程序設(shè)計(jì)的框架和庫(kù)青睞的一種方法是繞過(guò) Java 垃圾收集器,利用不屬于正常 Java 堆的內(nèi)存(稱為“堆外”內(nèi)存)。內(nèi)存使用正常的操作系統(tǒng)機(jī)制映射到持久存儲(chǔ),或者通過(guò)網(wǎng)絡(luò)連接復(fù)制到其他系統(tǒng)。

使用這種方法的明顯優(yōu)勢(shì)是對(duì)內(nèi)存的訪問(wèn)不受垃圾收集器的非確定性干預(yù)。缺點(diǎn)是管理在這些區(qū)域中創(chuàng)建的對(duì)象的生命周期成為應(yīng)用程序或庫(kù)的責(zé)任。

現(xiàn)代應(yīng)用程序的通用架構(gòu)在組件之間包含某種形式的通信,通?;谙鬟f。消息在通信過(guò)程中被序列化為 JSONYAML 等標(biāo)準(zhǔn)格式或從標(biāo)準(zhǔn)格式反序列化,提供此功能的庫(kù)通常可以引入高級(jí)別的對(duì)象分配。經(jīng)過(guò)仔細(xì)考慮,可以選擇經(jīng)過(guò)精心設(shè)計(jì)的庫(kù),以最大限度地減少新 Java 對(duì)象的創(chuàng)建,從而對(duì)性能產(chǎn)生積極影響。

從 Java 的早期開(kāi)始,對(duì)共享可變數(shù)據(jù)的并發(fā)訪問(wèn)就使用互斥鎖進(jìn)行同步。如果一個(gè)線程試圖獲取另一個(gè)線程持有的鎖,那么它會(huì)被阻塞,直到鎖被釋放。在多核環(huán)境中,可以使用不需要獲取線程阻塞的替代技術(shù)來(lái)實(shí)現(xiàn)同步,并且已經(jīng)表明,在大多數(shù)情況下,這對(duì)減少延遲有積極的影響。

編寫(xiě)此類代碼并不簡(jiǎn)單,但是,可以在標(biāo)準(zhǔn) Java 庫(kù)中的 Lock 接口后面進(jìn)行封裝,甚至可以進(jìn)一步定義允許通過(guò)標(biāo)準(zhǔn) API 進(jìn)行安全、無(wú)鎖并發(fā)訪問(wèn)的數(shù)據(jù)結(jié)構(gòu)。一些標(biāo)準(zhǔn)的 Java Collections 庫(kù)使用這種方法,盡管這對(duì)用戶是透明的。

Linux

公平地說(shuō),多年來(lái),Unix 的“實(shí)時(shí)”變體已經(jīng)為專門(mén)的應(yīng)用程序提供了不同的執(zhí)行環(huán)境。雖然這些通常是利基產(chǎn)品,但現(xiàn)在許多這些方法和功能在 Unix 和 Linux 的主流發(fā)行版中都可用。

最小化延遲的特性通常分為兩類,內(nèi)存管理和線程調(diào)度。

Linux 進(jìn)程中的所有內(nèi)存,包括 Java 的垃圾收集堆,都會(huì)被臨時(shí)“換出”到磁盤(pán),以便其他進(jìn)程可以在需要將內(nèi)存重新帶入之前將 RAM 用于自己的目的。這一切都會(huì)發(fā)生對(duì)進(jìn)程完全透明,內(nèi)存中的數(shù)據(jù)和后備存儲(chǔ)中的數(shù)據(jù)之間的訪問(wèn)時(shí)間差異可能有幾個(gè)數(shù)量級(jí)。當(dāng)然,堆外內(nèi)存也有同樣的行為。

但是,現(xiàn)代 Unix 和 Linux 系統(tǒng)允許標(biāo)記內(nèi)存區(qū)域,以便操作系統(tǒng)在尋找要從進(jìn)程中回收的區(qū)域時(shí)忽略它們。這意味著,對(duì)于該進(jìn)程中的那些內(nèi)存區(qū)域,內(nèi)存訪問(wèn)時(shí)間將是一致的(并且總體上被認(rèn)為更快)。不得不說(shuō),在繁忙的Java應(yīng)用程序中,訪問(wèn)進(jìn)程內(nèi)存的頻率會(huì)降低該內(nèi)存被分頁(yè)的可能性,但風(fēng)險(xiǎn)仍然存在。

以這種方式固定一個(gè)進(jìn)程的內(nèi)存意味著其他進(jìn)程的內(nèi)存更少,這可能會(huì)因此受到影響,但在“實(shí)時(shí)”世界中,我們必須有點(diǎn)自私!

為低延遲而設(shè)計(jì)的數(shù)據(jù)結(jié)構(gòu)通常會(huì)默認(rèn)或通過(guò)選項(xiàng)提供將其內(nèi)存鎖定或固定在 RAM 中的能力。

Java 程序中的線程,就像來(lái)自其他應(yīng)用程序甚至操作系統(tǒng)任務(wù)的線程一樣,可以訪問(wèn)由稱為調(diào)度程序的操作系統(tǒng)組件管理的 CPU。調(diào)度程序有一組策略,用于決定選擇哪些需要訪問(wèn) CPU 的線程(稱為 Runnable 線程)——通常 Runnable 線程比 CPU 多。

如前所述,Unix/Linux 中的傳統(tǒng)調(diào)度策略旨在支持交互式線程而不是 CPU 綁定線程。如果我們?cè)噲D運(yùn)行對(duì)延遲敏感的應(yīng)用程序,這對(duì)我們沒(méi)有幫助——我們希望我們的線程以某種方式優(yōu)先于其他非延遲敏感的線程。

現(xiàn)代 Unix/Linux 系統(tǒng)提供了可以提供這些功能的替代調(diào)度策略,通過(guò)允許將線程調(diào)度優(yōu)先級(jí)固定在高級(jí)別,以便它們?cè)诳蛇\(yùn)行時(shí)總是從其他線程接管 CPU 資源,這意味著它們可以更多地響應(yīng)事件迅速地。

但也可以進(jìn)一步影響調(diào)度程序的行為。通常,在管理線程時(shí)會(huì)使用所有可用的 CPU 資源。如今,可以更改調(diào)度程序使用哪些 CPU。我們可以從調(diào)度程序可用的 CPU 中完全移除 CPU,并將它們專門(mén)用于我們的專用線程。

或者,我們可以將 CPU 分成組,并將一組 CPU 與特定的線程組相關(guān)聯(lián)。此功能是 Linux 更通用的資源管理組件(稱為組)的一部分。它構(gòu)成了 Linux 對(duì)虛擬化的支持的一部分,并且是實(shí)現(xiàn)容器的關(guān)鍵,例如在現(xiàn)代環(huán)境中由 Docker 生成的容器。但是,它可以通過(guò)特定的系統(tǒng)調(diào)用用于一般應(yīng)用程序。

就像上面描述的內(nèi)存鎖定一樣,我們是自私的,因?yàn)檫@樣做顯然會(huì)對(duì)系統(tǒng)的其他部分產(chǎn)生負(fù)面影響。需要非常小心地配置以獲得最佳結(jié)果,因?yàn)殄e(cuò)誤的可能性很高,而且出錯(cuò)的后果可能很?chē)?yán)重。

結(jié)論

編寫(xiě)和部署低延遲應(yīng)用程序是一項(xiàng)高技能活動(dòng),不僅需要了解所使用的語(yǔ)言,還需要了解應(yīng)用程序運(yùn)行的環(huán)境。在本文中,我概述了一些需要考慮的領(lǐng)域,以及如何解決這些問(wèn)題。

資源

要詳細(xì)了解本文中討論的一些主題,請(qǐng)查看本書(shū)。

相關(guān)新聞

聯(lián)系我們
聯(lián)系我們
公眾號(hào)
公眾號(hào)
在線咨詢
分享本頁(yè)
返回頂部
北宁市| 长兴县| 离岛区| 西乡县| 微山县| 汝南县| 门源| 冕宁县| 邯郸市| 富锦市| 綦江县| 容城县| 阜宁县| 榆社县| 满城县| 黄山市| 弥勒县| 伊川县| 天峻县| 论坛| 阿克| 林西县| 边坝县| 梁平县| 青州市| 湖南省| 苏尼特左旗| 定安县| 昭平县| 滁州市| 宣汉县| 蛟河市| 宜兴市| 家居| 邛崃市| 邵阳市| 年辖:市辖区| 正蓝旗| 宁德市| 咸宁市| 资阳市|