近日,來自多倫多大學和 YScope 公司(為軟件系統提供創新的日志管理和故障排除工具。由一群計算機工程教授和博士創立)的 David Lion、多倫多大學 Adrian Chiu 和 Michael Stumm、多倫多大學和 YScope 公司 Ding Yuan 共同發布了一份《調查托管語言的運行時性能:為什么 JavaScript 和 Python 比 C++ 慢了 8 倍和 29 倍,而 Java 和 Go 卻能更快》(https://www.usenix.org/system/files/atc22-lion.pdf)的論文分析報告,深度剖析了不同編程語言運行時在代碼開發中真實的性能情況,由此方便開發者可以精確地測量執行任何字節碼指令所花費的時間等。
性能是系統軟件不得不面對的挑戰
在報告中,研究人員指出,自 2015 年以來,具有集成運行時環境的編程語言越來越受歡迎,其中,全球知名的代碼托管平臺 GitHub 上最受歡迎的三種語言分別是 JavaScript、Java 和 Python。
作為開發利器,編程語言幫助開發者快速構建各種應用程序和服務,也極大地提高了生產力。同時,這些語言自身也提供了各種功能,如動態類型檢查、帶有垃圾收集的內存管理,以及動態內存安全檢查等等。為此,研究人員用「托管語言」(managed languages)專業術語來指代這些類型的編程語言。
現實來看,托管語言越來越多地被用于實現性能至關重要的系統軟件上,如Hadoop 和 Spark 都在 Java 虛擬機(JVM)上運行,因為它們分別用 Java 和 Scala 實現;Kubernetes、etcd(分布式鍵值存儲)和 M3(由 Uber 建立的分布式時間序列數據庫和查詢引擎)都是用 Go 實現的。
當前,甚至連操作系統(OS)的內核 Biscuit 也是用 Go 實現的 。Openstack、Paypal、Instagram 和 Dropbox 都大量使用 Python,其中,Python 是 Dropbox "在后臺服務和桌面客戶端應用中使用最廣泛的語言",在一個存儲庫中就有近 400 萬行 Python 代碼;JavaScript 也被用于 Facebook 的 Bladerunner pub/sub 系統的性能關鍵路徑中。
在開發過程中,編程語言的性能在一開始很少會被考慮到項目中,部分原因是不少開發者認為性能問題可以在以后慢慢去解決,也許可以通過簡單地增加硬件來進行橫向擴展。
不過,隨著代碼產品或服務使用規模的擴大,服務變得越來越慢或者硬件成本變高,性能成為一個不容忽視的問題。這也是為什么 Stream 要放棄了 Python 而改用 Go、 Discord 從 Go 切換到 Rust、Twitter 從 Ruby on Rails 切換到 Scala 和 Java 的主要原因。
不少開發者往往為了提升性能,想破腦袋,但現實只有兩條路,一條是從現有的代碼中想盡辦法盡可能地做優化,另一條是思考使用的編程語言是否已經達到了性能極限,看看有沒有必要將舊的代碼移植到一個新的性能更高的語言上。
為了徹底解開系統軟件中不同編程語言導致的性能問題,研究人員決定以 C++ 為極限,對 Java、Go、JavaScript 和 Python 四種編程,還有應用最廣泛的運行時系統 CPython、OpenJDK。Node.js 與 JavaScript 的 V8 引擎進行深入的定量性能分析。
同時,研究人員還從頭開始建立了 6 個應用程序,并創建了一個名為
洞最有可能影響使用WebKit呈現引擎顯示網頁的任何IOS和macOS應用程序。到目前為止Apple仍然在調查。安全研究人員發現Safari使用的WebKit渲染引擎中存在一個漏洞,該漏洞會令使用IOS操作系統的iPhone和iPad系統崩潰并重新啟動。
可以通過加載使用特制CSS代碼的HTML頁面來利用此漏洞。CSS代碼不是很復雜,并嘗試將一種稱為backdrop-filter的CSS效果應用于一系列嵌套頁面段(DIV)。
背景過濾器是一種相對較新的CSS屬性,通過模糊或顏色移動到元素后面的區域來工作。這是一項繁重的處理任務,一些軟件工程師和Web開發人員推測,這種效果的渲染會對IOS的圖形處理庫造成影響,最終導致移動操作系統崩潰。
Sabri Haddouche是加密即時消息應用程序Wire的軟件工程師和安全研究員,也是他發現了這個漏洞,并在近日早些時候在Twitter上發布了概念驗證代碼。
此鏈接將使您的iOS設備崩潰,而此鏈接將顯示此漏洞背后的源代碼。Haddouche還在推特上發布了一個漏洞導致手機崩潰的視頻短片。Haddouche 在采訪中稱“攻擊使用webkit-backdrop-filter CSS屬性中的弱點,該屬性使用3D加速來處理它們背后的元素”。“通過使用具有該屬性的嵌套div,我們可以快速消耗所有圖形資源并凍結或內核恐慌OS。”Haddouche還表示該漏洞也會影響macOS系統,而不僅僅是iOS。
研究人員告訴媒體說:“利用當前的攻擊(僅限CSS / HTML),它只會凍結Safari一分鐘然后放慢速度。” “之后你就可以關閉標簽了。”“為了使它適用于macOS,它需要一個包含Javascript的修改版本,” “我沒有發布它的原因是,似乎Safari在強制重啟后仍然存在并且瀏覽器再次啟動,因此在惡意頁面再次執行時會破壞用戶的會話。”
研究人員表示,在Twitter上發布代碼之前,他已經通知了Apple這個問題。“我使用他們的安全產品電子郵件聯系了他們,”Haddouche告訴媒體“他們證實他們收到了這個問題并正在調查它。”
Haddouche告訴媒體稱他在研究多個瀏覽器上可靠的拒絕服務(DoS)錯誤時發現了這個漏洞。在本月初,Haddouche還發布了另一個利用一行JavaScript破壞Chrome和Chrome OS的漏洞。
另一方面,正如一位iOS開發人員告訴媒體的那樣,這個漏洞可能比以前想象的存在更廣泛。這是因為Apple強制App Store上列出的所有瀏覽器和支持HTML的應用程序都使用其WebKit渲染引擎,這意味著該問題很可能會導致任何能夠加載網頁的應用程序崩潰。
目前蘋果公司還未對這一事件做出正面回應。
里有一些 Javascript初學者應該知道的技巧和陷阱。如果你已經是專家了,順便溫習一下。
Javascript也只不過是一種編程語言。怎么可能出錯嘛?
1. 你有沒有嘗試給一組數字排序?
Javascript 的sort()函數在默認情況下使用字母數字(字符串Unicode碼點)排序。
所以[1,2,5,10].sort() 會輸出 [1, 10, 2, 5].
要正確的排序一個數組, 你可以用 [1,2,5,10].sort((a, b)=> a?—?b)
很簡單的解決方案, 前提是你得知道有這么個坑
2. new Date() 很棒
new Date() 可以接受:
沒有參數: 返回當前時間
一個參數 x: 返回1970年1月1日 + x 毫秒。 了解 Unix 的人知道為什么。
new Date(1, 1, 1) 返回 1901, 二月 , 1號/。因為,第一個參數表示1900年加1年,第二個參數表示這一年的第二個月(因此是二月)?—?腦回路正常的人會從1開始索引?—?,第三個參數很明顯是這個月的第一天,所以1?—?有時候索引確實從1開始?—?。
new Date(2016, 1, 1) 不會給1900年加上2016。它僅代表2016年。
3. Replace 并不“替代”
let s="bob" const replaced=s.replace('b', 'l') replaced==="lob" s==="bob"
我覺得這是一件好事,因為我不喜歡函數改變它們的輸入。 你還應該知道 replace 只會替換第一個匹配的字符串:
如果你想替換所有匹配的字符串,你可以使用帶/g標志的正則表達式 :
"bob".replace(/b/g, 'l')==='lol' // 替換所有匹配的字符串
4. 比較的時候要注意
// These are ok 'abc'==='abc' // true 1===1 // true // These are not [1,2,3]===[1,2,3] // false {a: 1}==={a: 1} // false {}==={} // false
原因:[1,2,3]和[1,2,3]是兩個獨立的數組。它們只是恰好包含相同的值。它們具有不同的引用,無法用===相比較。
5. 數組不是原始數據類型
typeof {}==='object' // true typeof 'a'==='string' // true typeof 1===number // true // But.... typeof []==='object' // true
如果你想知道你的變量是不是數組,你仍然可以用Array.isArray(myVar)
6. 閉包
這是一個很有名的面試題:
const Greeters=[] for (var i=0 ; i < 10 ; i++) { Greeters.push(function () { return console.log(i) }) } Greeters[0]() // 10 Greeters[1]() // 10 Greeters[2]() // 10
你是不是認為它會輸出 0, 1, 2… ? 你知道它為什么不是這樣輸出的嗎? 你會怎樣修改讓它輸出 0, 1, 2… ?
這里有兩種可能的解決方法:
用 let 替代 var. Boom. 解決了.
let和var的不同在于作用域。var的作用域是最近的函數塊,let的作用域是最近的封閉塊,封閉塊可以小于函數塊(如果不在任何塊中,則let和var都是全局的)。(來源)
替代方法: 用 bind:
Greeters.push(console.log.bind(null, i))
還有很多其他方法。這只是我的兩個首選
7. 談到 bind
你認為這個會輸出什么?
class Foo { constructor (name) { this.name=name } greet () { console.log('hello, this is ', this.name) } someThingAsync () { return Promise.resolve() } asyncGreet () { this.someThingAsync() .then(this.greet) } } new Foo('dog').asyncGreet()
如果你認為這個程序會崩潰提示 Cannot read property 'name' of undefined,給你一分。
原因: greet 沒有在正確的上下文中運行。同樣,這個問題依然有很多解決方案。
我個人喜歡
asyncGreet () { this.someThingAsync() .then(this.greet.bind(this)) }
這樣可以確保類的實例作為上下文調用greet。
如果你認為greet 不應該在實例上下文之外運行, 你可以在類的constructor中綁定它:
class Foo { constructor (name) { this.name=name this.greet=this.greet.bind(this) } }
你還應該知道箭頭函數(=> )可以用來保留上下文。這個方法也可以:
asyncGreet () { this.someThingAsync() .then(()=> { this.greet() }) }
盡管我認為最后一種方法并不優雅。
我很高興我們解決了這個問題。
總結
祝賀你,你現在可以放心地把你的程序放在互聯網上了。甚至運行起來可能都不會出岔子(但是通常會)Cheers \o/
*請認真填寫需求信息,我們會在24小時內與您取得聯系。