當(dāng)前位置:首頁 > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]國慶的時(shí)候閑來無事,就隨手寫了一點(diǎn)之前說的比賽的代碼,目標(biāo)就是保住前100混個(gè)大賽的文化衫就行了。現(xiàn)在還混在前50的隊(duì)伍里面,穩(wěn)的一比。其實(shí)我覺得大家做柔性負(fù)載均衡那題的思路其實(shí)都不會(huì)差太多,就看誰能把關(guān)鍵的信息收集起來并利用上了。由于是基于Dubbo去做的嘛,調(diào)試的過程中,寫著...


國慶的時(shí)候閑來無事,就隨手寫了一點(diǎn)之前說的比賽的代碼,目標(biāo)就是保住前 100 混個(gè)大賽的文化衫就行了。

現(xiàn)在還混在前 50 的隊(duì)伍里面,穩(wěn)的一比。

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
其實(shí)我覺得大家做柔性負(fù)載均衡那題的思路其實(shí)都不會(huì)差太多,就看誰能把關(guān)鍵的信息收集起來并利用上了。

由于是基于 Dubbo 去做的嘛,調(diào)試的過程中,寫著寫著我看到了這個(gè)地方:

org.apache.dubbo.rpc.protocol.AbstractInvoker#waitForResultIfSync

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
先看我框起來的這一行代碼,aysncResult 的里面有有個(gè) CompletableFuture ,它調(diào)用的是帶超時(shí)時(shí)間的 get() 方法,超時(shí)時(shí)間是 Integer.MAX_VALUE,理論上來說效果也就等同于 get() 方法了。

從我直觀上來說,這里用 get() 方法也應(yīng)該是沒有任何毛病的,甚至更好理解一點(diǎn)。

但是,為什么沒有用 get() 方法呢?

其實(shí)方法上的注釋已經(jīng)寫到原因了,就怕我這樣的人產(chǎn)生了這樣的疑問:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
抓住我眼球的是這這幾個(gè)單詞:

have serious performance drop。

性能嚴(yán)重下降。

大概就是說我們必須要調(diào)用 java.util.concurrent.CompletableFuture#get(long, java.util.concurrent.TimeUnit) 而不是 get() 方法,因?yàn)?get 方法被證明會(huì)導(dǎo)致性能嚴(yán)重的下降。

對于 Dubbo 來說, waitForResultIfSync 方法,是主鏈路上的方法。

我個(gè)人覺得保守一點(diǎn)說,可以說 90% 以上的請求都會(huì)走到這個(gè)方法來,阻塞等待結(jié)果。所以如果該方法如果有問題,則會(huì)影響到 Dubbo 的性能。

Dubbo 作為中間件,有可能會(huì)運(yùn)行在各種不同的 JDK 版本中,對于特定的 JDK 版本來說,這個(gè)優(yōu)化確實(shí)是對于性能的提升有很大的幫助。

就算不說 Dubbo ,我們用到 CompletableFuture 的時(shí)候,get() 方法也算是我們常常會(huì)用到的一個(gè)方法。

另外,這個(gè)方法的調(diào)用鏈路我可太熟悉了。

因?yàn)槲覂赡昵皩懙牡谝黄娞?hào)文章就是探討 Dubbo 的異步化改造的。

當(dāng)年,這部分代碼肯定不是這樣的,至少?zèng)]有這個(gè)提示。

因?yàn)槿绻羞@個(gè)提示的話,我肯定第一次寫的時(shí)候就注意到了。

果然,我去翻了一下,雖然圖片已經(jīng)很模糊了,但是還是能隱約看到,之前確實(shí)是調(diào)用的 get() 方法:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!

我還稱之為最“騷”的一行代碼。

因?yàn)檫@一行的代碼就是 Dubbo 異步轉(zhuǎn)同步的關(guān)鍵代碼。

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
前面只是一個(gè)引子,本文不會(huì)去寫 Dubbo 相關(guān)的知識(shí)點(diǎn)。

主要寫寫 CompletableFuture 的 get() 到底有啥問題。

放心,這個(gè)點(diǎn)面試肯定不考。

只是你知道這個(gè)點(diǎn)后,恰好你的 JDK 版本是沒有修復(fù)之前的,寫代碼的時(shí)候可以稍微注意一下。

學(xué) Dubbo 在方法調(diào)用的地方加上一樣的 NOTICE,直接把逼格拉滿。等著別人問起來的時(shí)候,你再娓娓道來。

或者不經(jīng)意間看到別人這樣寫的時(shí)候,輕飄飄的說一句:這里有可能會(huì)有性能問題,可以去了解一下。

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!

啥性能問題?

根據(jù) Dubbo 注釋里面的這點(diǎn)信息,我也不知道啥問題,但是我知道去哪里找問題。

這種問題肯定在 openJDK 的 bug 列表里面記錄有案,所以第一站就是來這里搜索一下關(guān)鍵字:

https://bugs.openjdk.java.net/projects/JDK/issues/

一般來說,都是一些陳年老 BUG,需要搜索半天才能找到自己想要的信息。

但是,這次運(yùn)氣好到爆棚,彈出來的第一個(gè)就是我要找的東西,簡直是搞的我都有點(diǎn)不習(xí)慣了,這難道是傳說中的國慶獻(xiàn)禮嗎,不敢想不敢想。

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
標(biāo)題就是:對CompletableFuture的性能改進(jìn)。

里面提到了編號(hào)為 8227019 的 BUG。

https://bugs.openjdk.java.net/browse/JDK-8227019

我們一起看看這個(gè) BUG 描述的是啥玩意。

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
標(biāo)題翻譯過來,大概意思就是說 CompletableFuture.waitingGet 方法里面有一個(gè)循環(huán),這個(gè)循環(huán)里面調(diào)用了 Runtime.availableProcessors 方法。且這個(gè)方法被調(diào)用的很頻繁,這樣不好。

在詳細(xì)描述里面,它提到了另外的一個(gè)編號(hào)為 8227006 的 BUG,這個(gè) BUG 描述的就是為什么頻繁調(diào)用 availableProcessors 不太好,但是這個(gè)我們先按下不表。

先研究一下他提到的這樣一行代碼:

?spins?=?(Runtime.getRuntime().availableProcessors()?>?1)??
????????????????????1?<
他說位于 waitingGet 里面,我們就去看看到底是怎么回事嘛。

但是我本地的 JDK 的版本是 1.8.0_271,其 waitingGet 源碼是這樣的:

java.util.concurrent.CompletableFuture#waitingGet

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
先不管這幾行代碼是啥意思吧,反正我發(fā)現(xiàn)沒有看到 bug 中提到的代碼,只看到了 spins=SPINS ,雖然 SPINS 調(diào)用了 Runtime.getRuntime().availableProcessors() 方法,但是該字段被 static 和 final 修飾了,也就不存在 BUG 中描述的“頻繁調(diào)用”了。

于是我意識(shí)到我的版本是不對的,這應(yīng)該是被修復(fù)之后的代碼,所以去下載了幾個(gè)之前的版本。

最終在 JDK 1.8.0_202 版本中找到了這樣的代碼:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
和前面截圖的源碼的差異就在于前者多了一個(gè) SPINS 字段,把 Runtime.getRuntime().availableProcessors() 方法的返回緩存了起來。

我一定要找到這行代碼的原因就是要證明這樣的代碼確實(shí)是在某些 JDK 版本中出現(xiàn)過。

好了,現(xiàn)在我們看一下 waitingGet 方法是干啥的。

首先,調(diào)用 get() 方法的時(shí)候,如果 result 還是 null 那么說明異步線程執(zhí)行的結(jié)果還沒就緒,則調(diào)用 waitingGet 方法:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
而來到 waitingGet 方法,我們只關(guān)注 BUG 相關(guān)這兩個(gè)分支判斷:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
首先把 spins 的值初始化為 -1。

然后當(dāng) result 為 null 的時(shí)候,就一直進(jìn)行 while 循環(huán)。

所以,如果進(jìn)入循環(huán),第一次一定會(huì)調(diào)用 availableProcessors 方法。然后發(fā)現(xiàn)是多處理器的運(yùn)行環(huán)境,則把 spins 置為 1<<8 ,即 256。

然后再次進(jìn)行循環(huán),走入到 spins>0 的分支判斷,接著做一個(gè)隨機(jī)運(yùn)算,隨機(jī)出來的值如果大于等于 0 ,則對 spins 進(jìn)行減一操作。

只有減到 spins 為 0 的時(shí)候才會(huì)進(jìn)入到后面的這些被我框起來的邏輯中:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
也就是說這里就是把 spins 從 256 減到 0,且由于隨機(jī)函數(shù)的存在,循環(huán)次數(shù)一定是大于 256 次的。

但是還有一個(gè)大前提,那就是每次循環(huán)的時(shí)候都會(huì)去判斷循環(huán)條件是否還成立。即判斷 result 是否還是 null。為 null 才會(huì)繼續(xù)往下減。

所以,你說這段代碼是在干什么事兒?

其實(shí)注釋上已經(jīng)寫的很清楚了:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
Use brief spin-wait on multiprocessors。

brief,這是一個(gè)四級詞匯哈,得記住,要考的。就是“短暫”的意思,是一個(gè)不規(guī)則動(dòng)詞,其最高級是 briefest。

對了,spin 這個(gè)單詞大家應(yīng)該認(rèn)識(shí)吧,前面忘記給大家教單詞了,就一起講了,看小黑板:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
所以注釋上說的就是:如果是多處理器,則使用短暫的自旋等待一下。

從 256 減到 0 的過程,就是這個(gè)“brief spin-wait”。

但是仔細(xì)一想,在自旋等待的這個(gè)過程中,availableProcessors 方法只是在第一次進(jìn)入循環(huán)的時(shí)候調(diào)用了一次。

那為什么說它耗費(fèi)性能呢?

是的,確實(shí)是調(diào)用 get() 方法的只調(diào)用了一次,但是你架不住 get() 方法被調(diào)用的次數(shù)多啊。

就拿 Dubbo 舉例,絕大部分情況下的大家的調(diào)用方式都用的是默認(rèn)的同步調(diào)用的方案。所以每一次調(diào)用都會(huì)到異步轉(zhuǎn)同步這里阻塞等待結(jié)果,也就說每次都會(huì)調(diào)用一次 get() 方法,即 availableProcessors 方法就會(huì)被調(diào)用一次。

那么解決方案是什么呢?

在前面我已經(jīng)給大家看了,就是把 availableProcessors 方法的返回值找個(gè)字段給緩存起來:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
但是后面跟了一個(gè)“problem”。

這個(gè)“problem”就是說如果我們把多處理器這個(gè)值緩存起來了,假設(shè)程序運(yùn)行的過程中出現(xiàn)了從多處理器到單處理器的運(yùn)行環(huán)境變化這個(gè)值就不準(zhǔn)確了,雖然這是一個(gè)不太可能的變化。但是即使這個(gè)“problem”真的發(fā)生了也沒有關(guān)系,它只是會(huì)導(dǎo)致一個(gè)小小的性能損失。

所以就出現(xiàn)了前面大家看到的這樣的代碼,這就是 “we can cache this value in a field”:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
而體現(xiàn)到具體的代碼變更是這樣的:

http://cr.openjdk.java.net/~shade/8227018/webrev.01/src/share/classes/java/util/concurrent/CompletableFuture.java.udiff.html

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
所以,當(dāng)你去看這部分源碼的時(shí)候,你會(huì)看到 SPINS 字段上其實(shí)還有很長一段話,是這樣的:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
給大家翻譯一下:

1.在 waitingGet 方法中,進(jìn)行阻塞操作前,進(jìn)行旋轉(zhuǎn)。

2.沒有必要在單處理器上進(jìn)行旋轉(zhuǎn)。

3.調(diào)用 Runtime.availableProcessors 方法的成本是很高的,所以在此緩存該值。但是這個(gè)值是首次初始化時(shí)可用的 CPU 的數(shù)量。如果某系統(tǒng)在啟動(dòng)時(shí)只有一個(gè) CPU 可以用,那么 SPINS 的值會(huì)被初始化為 0,即使后面再使更多的 CPU 在線,也不會(huì)發(fā)生變化。

當(dāng)你有了前面的 BUG 的描述中的鋪墊之后,你就明白了為什么這里寫上了這么一大段話。

有的同學(xué)就真的去翻代碼,也許你看到的是這樣的:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
什么情況?根本就看不到 SPINS 相關(guān)的代碼啊,這不是欺騙老實(shí)人嗎?

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!

你別慌啊,猴急猴急的,我這不是還沒說完嘛?

我們再把目光放到圖片中的這句話上:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
只需要在 JDK 8 中進(jìn)行這個(gè)修復(fù)即可,因?yàn)?JDK 9 和更高版本的代碼都不是這樣的寫的了。

比如在 JDK 9 中,直接拿掉了整個(gè) SPINS 的邏輯,不要這個(gè)短暫的自旋等待了:

http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/f3af17da360b

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
雖然,拿掉了這個(gè)短暫的自旋等待,但是其實(shí)也算是學(xué)習(xí)了一個(gè)騷操作。

比如怎么在不引入時(shí)間的前提下,做出一個(gè)自旋等待的效果?

答案就是被拿掉的這段代碼。

但是有一說一,我第一次看到這個(gè)代碼的時(shí)候我就覺得別扭。這一個(gè)短短的自旋能延長多少時(shí)間呢?

加入這個(gè)自旋,是為了稍晚一點(diǎn)執(zhí)行后續(xù)邏輯中的 park 代碼,這個(gè)稍重一點(diǎn)的操作。但是我覺得這個(gè) “brief spin-wait” 的收益其實(shí)是微乎其微的。

所以我也理解為什么后續(xù)直接把這一整坨代碼拿掉了。而拿掉這一坨代碼的時(shí)候,其實(shí)作者并沒有意識(shí)到這里有 BUG。

這里提到的作者,其實(shí)就是 Doug Lea 老爺子。

我為什么敢這樣說呢?

那必然是有證據(jù)的呀。

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!

依據(jù)就在這個(gè) BUG 鏈接里面提到的編號(hào)為 8227018 的 BUG 中,它們其實(shí)描述的是同一個(gè)事情:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
這里面有這樣一段對話,出現(xiàn)了 David Holmes 和 Doug Lea:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
Holmes 在這里面提到了 “cache this value in a field” 的解決方案,并得到了 Doug 的同意。

Doug 說:JDK 9 已經(jīng)不用 spin 了。

所以,我個(gè)人理解是 Doug 在不知道這個(gè)地方有 BUG 的情況下,拿掉了 SPIN 的邏輯。至于是出于什么考慮,我猜測是收益確實(shí)不大,且代碼具有一定的迷惑性。還不如拿掉之后,理解起來直觀一點(diǎn)。

Doug Lea 大家都耳熟能詳, David Holmes 是誰呢?

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!

《Java 并發(fā)編程實(shí)戰(zhàn)》的作者之一,端茶就完事了。

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
而你要是對我以前的文章印象足夠深刻,那么你會(huì)發(fā)現(xiàn)早在《Doug Lea在J.U.C包里面寫的BUG又被網(wǎng)友發(fā)現(xiàn)了?!愤@篇文章里面,他就已經(jīng)出現(xiàn)過了:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
老朋友又出現(xiàn)了,建議鐵汁們把夢幻聯(lián)動(dòng)打在公屏上。

到底啥原因?

前面噼里啪啦的說了這么大一段,核心思想其實(shí)就是 Runtime.availableProcessors 方法的調(diào)用成本高,所以在 CompletableFuture.waitingGet 方法中不應(yīng)該頻繁調(diào)用這個(gè)方法。

但是 availableProcessors 為什么調(diào)用成本就高了,依據(jù)是啥,得拿出來看看啊!

這一小節(jié),就給大家看看依據(jù)是什么。

依據(jù)就在這個(gè) BUG 描述中:

https://bugs.openjdk.java.net/browse/JDK-8157522

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
標(biāo)題上說:在 linux 環(huán)境下,Runtime.availableProcessors 執(zhí)行時(shí)間增加了 100 倍。

增加了 100 倍,肯定是有兩個(gè)不同的版本的對比,那么是哪兩個(gè)版本呢?

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
在 1.8b191 之前的 JDK 版本上,下面的示例程序可以實(shí)現(xiàn)每秒 400 多萬次對 Runtime.availableProcessors 的調(diào)用。

但在 JDK build 1.8b191 和所有后來的主要和次要版本(包括11)上,它能實(shí)現(xiàn)的最大調(diào)用量是每秒4萬次左右,性能下降了100倍。

這就導(dǎo)致了 CompletableFuture.waitingGet 的性能問題,它在一個(gè)循環(huán)中調(diào)用了 Runtime.availableProcessors。因?yàn)槲覀兊膽?yīng)用程序在異步代碼中表現(xiàn)出明顯的性能問題,waitingGet 就是我們最初發(fā)現(xiàn)問題的地方。

測試代碼是這樣的:

??public?static?void?main(String[]?args)?throws?Exception?{
????????AtomicBoolean?stop?=?new?AtomicBoolean();
????????AtomicInteger?count?=?new?AtomicInteger();

????????new?Thread(()?->?{
????????????while?(!stop.get())?{
????????????????Runtime.getRuntime().availableProcessors();
????????????????count.incrementAndGet();
????????????}
????????}).start();

????????try?{
????????????int?lastCount?=?0;
????????????while?(true)?{
????????????????Thread.sleep(1000);
????????????????int?thisCount?=?count.get();
????????????????System.out.printf("%s?calls/sec%n",?thisCount?-?lastCount);
????????????????lastCount?=?thisCount;
????????????}
????????}
????????finally?{
????????????stop.set(true);
????????}
????}
按照 BUG 提交者的描述,如果你在 64 位的 Linux 上,分別用 JDK 1.8b182 和 1.8b191 版本去跑,你會(huì)發(fā)現(xiàn)有近 100 倍的差異。

至于為什么有 100 倍的性能差異,一位叫做 Fairoz Matte 的老哥說他調(diào)試了一下,定位到問題出現(xiàn)在調(diào)用 “OSContainer::is_containerized()” 方法的時(shí)候:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
而且他也定位到了問題出現(xiàn)的最開始的版本號(hào)是 8u191 b02,在這個(gè)版本之后的代碼都會(huì)有這樣的問題。

帶來問題的那次版本升級干的事是改進(jìn) docker 容器檢測和資源配置的使用。

所以,如果你的 JDK 8 是 8u191 b02 之前的版本,且系統(tǒng)調(diào)用并發(fā)非常高,那么恭喜你,有機(jī)會(huì)踩到這個(gè)坑。

然后,下面幾位大佬基于這個(gè)問題給出了很多解決方案,并針對各種解決方案進(jìn)行討論。

有的解決方案,聽起來就感覺很麻煩,需要編寫很多的代碼,我就不一一解讀了。

最終,大道至簡,還是選擇了實(shí)現(xiàn)起來比較簡單的 cache 方案,雖然這個(gè)方案也有一點(diǎn)瑕疵,但是出現(xiàn)的概率非常低且是可以接受的。

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!

再看get方法

現(xiàn)在我們知道了這個(gè)沒有卵用的知識(shí)點(diǎn)之后,我們再看看為什么調(diào)用帶超時(shí)時(shí)間的 get() 方法,沒有這個(gè)問題。

java.util.concurrent.CompletableFuture#get(long, java.util.concurrent.TimeUnit)

首先可以看到內(nèi)部調(diào)用的方法都不一樣了:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
有超時(shí)時(shí)間的 get() 方法,內(nèi)部調(diào)用的是 timedGet 方法,入?yún)⒕褪浅瑫r(shí)時(shí)間。

點(diǎn)進(jìn) timedGet 方法就知道為什么調(diào)用帶超時(shí)時(shí)間的 get() 方法沒有問題了:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
在代碼的注釋里面已經(jīng)把答案給你寫好了:我們故意不在這里旋轉(zhuǎn)(像waitingGet那樣),因?yàn)樯厦鎸?nanoTime() 的調(diào)用很像一個(gè)旋轉(zhuǎn)。

可以看到在該方法內(nèi)部,根本就沒有對 Runtime.availableProcessors 的調(diào)用,所以也就不存在對應(yīng)的問題。

現(xiàn)在,我們回到最開始的地方:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
那么你說,下面的 asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS) 如果我們改成 asyncResult.get() 效果還是一樣的嗎?

肯定是不一樣的。

再說一次:Dubbo 作為開源的中間件,有可能會(huì)運(yùn)行在各種不同的 JDK 版本中,且該方法是它主鏈路上的核心代碼,對于特定的 JDK 版本來說,這個(gè)優(yōu)化確實(shí)是對于性能的提升有很大的幫助。

所以寫中間件還是有點(diǎn)意思哈。

最后,再送你一個(gè)為 Dubbo 提交源碼的機(jī)會(huì)。

在其下面的這個(gè)類中:

org.apache.dubbo.rpc.AsyncRpcResult

還是存在這兩個(gè)方法:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
但是上面的 get() 方法只有測試類在調(diào)用了:

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
完全可以把它們?nèi)扛牡粽{(diào)用 get(long timeout, TimeUnit unit) 方法,然后把 get() 方法直接刪除了。

我覺得肯定是能被 merge 的。

如果你想為開源項(xiàng)目做貢獻(xiàn),熟悉一下流程,那么這是一個(gè)不錯(cuò)的小機(jī)會(huì)。

被 merge 后你就可以去吹牛了,畢竟是為 Apache 頂級開源項(xiàng)目貢獻(xiàn)過源碼的人,說話音調(diào)都可以加高點(diǎn)。

看完JDK并發(fā)包源碼的這個(gè)性能問題,我驚了!
好了,本文的技術(shù)部分就到這里啦。

下面這個(gè)環(huán)節(jié)叫做[荒腔走板],技術(shù)文章后面我偶爾會(huì)記錄、分享點(diǎn)生活相關(guān)的事情,和技術(shù)毫無關(guān)系。我知道看起來很突兀,但是我喜歡,因?yàn)檫@是一個(gè)普通博主的生活氣息。


本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉