bl双性强迫侵犯h_国产在线观看人成激情视频_蜜芽188_被诱拐的少孩全彩啪啪漫画

iOSApp使用GCD導(dǎo)致的卡頓現(xiàn)象怎么辦-創(chuàng)新互聯(lián)

這篇文章主要介紹了iOS App使用GCD導(dǎo)致的卡頓現(xiàn)象怎么辦,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

創(chuàng)新互聯(lián)主要從事網(wǎng)頁(yè)設(shè)計(jì)、PC網(wǎng)站建設(shè)(電腦版網(wǎng)站建設(shè))、wap網(wǎng)站建設(shè)(手機(jī)版網(wǎng)站建設(shè))、成都響應(yīng)式網(wǎng)站建設(shè)、程序開發(fā)、網(wǎng)站優(yōu)化、微網(wǎng)站、重慶小程序開發(fā)等,憑借多年來在互聯(lián)網(wǎng)的打拼,我們?cè)诨ヂ?lián)網(wǎng)網(wǎng)站建設(shè)行業(yè)積累了豐富的成都做網(wǎng)站、成都網(wǎng)站制作、網(wǎng)站設(shè)計(jì)、網(wǎng)絡(luò)營(yíng)銷經(jīng)驗(yàn),集策劃、開發(fā)、設(shè)計(jì)、營(yíng)銷、管理等多方位專業(yè)化運(yùn)作于一體。

最近在調(diào)研 iOS app 中存在的各種卡頓現(xiàn)象以及解決方法。

iOS App 出現(xiàn)卡頓(stall)的概率可能超出大部分人的想象,尤其是對(duì)于大公司旗艦型 App。一方面是由于業(yè)務(wù)功能不停累積,各個(gè)產(chǎn)品團(tuán)隊(duì)之間缺乏協(xié)調(diào),大家都忙著增加功能,系統(tǒng)資源出現(xiàn)瓶頸。另一方面的原因是老設(shè)備更新?lián)Q代太慢,iOS 設(shè)備的耐用度極好,現(xiàn)在還有不少 iPhone 4S 在服役,iPhone 6 作為問題設(shè)備持有量很高,據(jù)估計(jì),現(xiàn)在 iPhone 6s 以前的設(shè)備占有比高達(dá) 40%。

所以,如果嘗試在線上 App 加入卡頓檢測(cè)的工具,你會(huì)發(fā)現(xiàn)卡頓出現(xiàn)的概率高的驚人。但卡頓的檢測(cè)就修復(fù)并不簡(jiǎn)單,主要是因?yàn)殡y以在開發(fā)設(shè)備上復(fù)現(xiàn)。

之前寫過一篇介紹主線程卡頓監(jiān)控的文章,好像現(xiàn)在主流的做法都是通過監(jiān)控 Runloop 事件回調(diào),檢查進(jìn)入回調(diào)的時(shí)間間隔是否超過 Threshold,超過則記錄當(dāng)前 App 所有線程的 call stack。

我前段時(shí)間從后臺(tái)上報(bào)的卡頓日志里看到這樣一個(gè) call stack:

> 0 libsystem_kernel.dylib __workq_kernreturn
> 1 libsystem_pthread.dylib _pthread_workqueue_addthreads
> 2 libdispatch.dylib _dispatch_queue_wakeup_global_slow
> 3 libdispatch.dylib _dispatch_queue_wakeup_with_qos_slow
> 4 libdispatch.dylib dispatch_async

也就是說卡頓出現(xiàn)在 dispatch_async,以我現(xiàn)有對(duì)于 GCD 的認(rèn)知,dispatch_async 是絕無(wú)可能出現(xiàn)卡頓的。dispatch_async 的主要任務(wù)是從系統(tǒng)線程池里取出一個(gè)工作線程,并將 block 放到該線程里去執(zhí)行。

上述 call stack 確確實(shí)實(shí)的出現(xiàn)了,而且樣本數(shù)量還不少,最后一個(gè)函數(shù)明顯是一個(gè)內(nèi)核調(diào)用。從函數(shù)名字猜測(cè),可能是 GCD 嘗試從線程池里獲取線程,但已有線程都在執(zhí)行狀態(tài),所以向系統(tǒng)內(nèi)核申請(qǐng)創(chuàng)建新的線程。但創(chuàng)建線程的內(nèi)核調(diào)用會(huì)很慢嗎?會(huì)慢到讓主線程出現(xiàn)卡頓的程度?帶著疑問我搜索了大量相關(guān)資料,最后比較相關(guān)的有這樣一篇文章:http://newosxbook.com/articles/GCD.html

其中有這樣一段話:

This isn't due to 10.9's GCD being different - rather, it demonstrates the true asynchronous nature of GCD: The main thread has yet to return from requesting the worker (which it does by pthread_workqueue_addthreads_np, as I'll describe later), and already the worker thread has spawned and is mid execution, possibly on another CPU core. The exact state of the main thread with respect to the worker is largely unpredictable.

作者認(rèn)為,GCD 申請(qǐng)到的線程有可能是一個(gè)正在處理其他任務(wù)的 thread,main thread 需要等待這個(gè)忙碌的線程返回才能繼續(xù)執(zhí)行,我對(duì)這種說法存疑。

最后求助無(wú)門的狀況下,我決定使用一次寶貴的 TSL 機(jī)會(huì),直接向 Apple 的工程師求教。這里不得不提下,向 Apple 尋求 technical support 是非常寶貴而且可行的方案,每個(gè)開發(fā)者賬號(hào)每年都有 2 次機(jī)會(huì),不用非??上?。

我把問題拋過去后,得到一位 Apple 內(nèi)核團(tuán)隊(duì)工程師的回復(fù),我將精簡(jiǎn)過的回復(fù)以問答的形式展示和大家分享:

Q: looks like even if it's async dispatching, the main thread still has to wait for the other thread to return, during which time, the other thread happen to be in mid execution of sth. this confuses me, what exactly is the main thread waiting for?

為什么主線程需要等待 dispatch_async 返回,主線程到底在等待什么?

A: It's hard to say with just a user space backtrace. Frame 0 has clearly sent the current thread into the kernel, and this specific kernel call is /way/ too complex to analyse from outside [1].

從用戶態(tài)調(diào)用棧無(wú)法得出答案,內(nèi)核可能的狀態(tài)過于復(fù)雜。

Q: I know it's suggested that we create limited amount of serial queue,and use target queue probably. but what could happen if we don't follow that rule?

Apple 一直推薦自己創(chuàng)建 serial GCD queue 的時(shí)候,一定要控制數(shù)量,而且最好設(shè)置 target queue,否則會(huì)出現(xiàn)問題,但會(huì)出現(xiàn)什么問題我一直很好奇,這次借著機(jī)會(huì)一起問了。

A:

* On macOS, where the system is happier to over commit, you end up with a thread explosion. That in turn can lead to problems running out of memory, running out of Mach ports, and so on.

* On iOS, which is not happy about over committing, you find that the latency between a block being queued and it running can skyrocket. This can, in turn, have knock-on effects. For example, the last time I looked at a problem like this I found that `NSOperationQueue` was dispatching blocks to the global queue for internal maintenance tasks, so when one subsystem within the app consumed all the dispatch worker threads other subsystems would just stall horribly.

Note: In the context of dispatch, an “over commit” is where the system had to allocate more threads to a queue then there are CPU cores. In theory this should never be necessary because work you dispatch to a queue should never block waiting for resources. In practice it's unavoidable because, at a minimum, the work you queue can end up blocking on the VM subsystem.

Despite this, it's still best to structure your code to avoid the need for over committing, especially when the over commit doesn't buy you anything. For example, code like this:

group = dispatch_group_create();
for (url in urlsToFetch) {
  dispatch_group_enter(group);
  dispatch_async(dispatch_get_global_queue(…), ^{
    … fetch `url` synchronously …
    dispatch_group_leave(group);
  });
}
dispatch_group_wait(group, …);

is horrible because it ties up 10 dispatch worker threads for a very long time without any benefit. And while this is an extreme example — from dispatch's perspective, networking is /really/ slow — there are less extreme examples that are similarly problematic. From dispatch's perspective, even the disk drive is slow (-:

這段回復(fù)很有意思。閱讀過 GCD 源碼的同學(xué)會(huì)知道,所有默認(rèn)創(chuàng)建的 GCD queue 都有一個(gè)優(yōu)先級(jí),但其實(shí)每個(gè)優(yōu)先級(jí)對(duì)應(yīng)兩個(gè) queue,比如一個(gè)是 default-priority, 那么另一個(gè)就是 default-priority-overcommit。dispatch_async 的時(shí)候,會(huì)首先將任務(wù)丟進(jìn) default-priority 隊(duì)列,如果隊(duì)列滿了,就轉(zhuǎn)而丟進(jìn) default-priority-overcommit。

在 Mac 系統(tǒng)里,GCD 允許 overcommit,意味著每次 dispatch_async 都會(huì)創(chuàng)建一個(gè)新線程,即使 over commit 了,這些過量的線程會(huì)根據(jù)優(yōu)先級(jí)來競(jìng)爭(zhēng) CPU 資源。

而在 iOS 系統(tǒng)里,GCD 會(huì)控制 overcommit,如果某個(gè)優(yōu)先級(jí)隊(duì)列 over commit 里,那么排在后面的任務(wù)就會(huì)處于等待狀態(tài)。移動(dòng)設(shè)備 CPU 資源比較緊張,這種設(shè)計(jì)合乎常理。

所以如果在 iOS 里創(chuàng)建過多的 serial queue,那么后面提交的任務(wù)可能就會(huì)一直處于等待狀態(tài)。這也是為什么我們需要嚴(yán)格控制 queue 的數(shù)量和層級(jí)關(guān)系,最好是 App 當(dāng)中每個(gè)子系統(tǒng)只能分配固定數(shù)量和優(yōu)先級(jí)的 queue,從而避免 thread explosion 導(dǎo)致的代碼無(wú)法及時(shí)執(zhí)行問題。

Q:I know the system watchdog can kill an app if the main thread is taking too long to respond. I also heard rumors that there are two other cases that may gets your app killed by watchdog. the first is too many new threads are being created like by random usage of dispatching work to global concurrent queue? the second case is if CPU has been kept too busy like 100% for too long, watchdog kills app too?

我借機(jī)問了下系統(tǒng) watchdong 強(qiáng)殺 App 的原因,因?yàn)榉婚g一直有傳聞是除了主線程長(zhǎng)時(shí)間沒反應(yīng)之外,創(chuàng)建過多的線程和 CPU 長(zhǎng)時(shí)間超負(fù)荷運(yùn)轉(zhuǎn)也會(huì)導(dǎo)致被強(qiáng)殺。

A:I'm not aware of any specific watchdog check along those lines, but it's not hard to imagine that the above-mentioned knock-on effects might jam up your app sufficiently for the watchdog to kill it for other reasons. Running the CPU for too long generates a crash report but it doesn't actually kill the app. It's essentially a ‘warning' crash report about the problem.

創(chuàng)建過多線程不會(huì)直接導(dǎo)致 watchdog 強(qiáng)殺,但過多線程有可能導(dǎo)致主線程得不到及時(shí)處理,而因?yàn)槠渌虮?kill。而 CPU 長(zhǎng)時(shí)間過載并不會(huì)導(dǎo)致強(qiáng)殺,但系統(tǒng)會(huì)生成一個(gè) report 來警告開發(fā)者。我確實(shí)看到過不少這類 ‘this is not a crash' 的 crash 日志。

另外還有一些問答,和我當(dāng)前疑問并不直接相關(guān)所以略去。最后再貼一段比較有意思的回復(fù),在閱讀之前大家可以自己先思考下:

dispatch_async(myQueue, ^{
 // line A
});
// line B

line A 和 line B 誰(shuí)先執(zhí)行?

Consider a snippet like this:

dispatch_async(myQueue, ^{
 // line A
});
// line B

there's clearly a race condition between lines A and B, that is, between the `dispatch_async` returning and the block running on the queue. This can pan out in multiple ways, including:

* If `myQueue` (which we're assuming is a serial queue) is busy, A has to wait so B will definitely run before A.

* If `myQueue` is empty, there's no idle CPU, and `myQueue` has a higher priority then the thread that called `dispatch_async`, you could imagine the kernel switching the CPU to `myQueue` so that it can run A.

* The thread that called `dispatch_async` could run out of its time quantum after scheduling B on `myQueue` but before returning from `dispatch_async`, which again results in A running before B.

* If `myQueue` is empty and there's an idle CPU, A and B could end up running simultaneously.

答案

其實(shí)最后我也沒有得到我想要的準(zhǔn)確的答案,可能正如回復(fù)里所說,情況有很多而且過于復(fù)雜,沒法通過一個(gè)用戶態(tài)的 call stack 簡(jiǎn)單推知內(nèi)核的狀態(tài),但有些有價(jià)值的信息還是得以大致理清:

信息一

iOS 系統(tǒng)本身是一個(gè)資源調(diào)度和分配系統(tǒng),CPU,disk IO,VM 等都是稀缺資源,各個(gè)資源之間會(huì)互相影響,主線程的卡頓看似 CPU 資源出現(xiàn)瓶頸,但也有可能內(nèi)核忙于調(diào)度其他資源,比如當(dāng)前正在發(fā)生大量的磁盤讀寫,或者大量的內(nèi)存申請(qǐng)和清理,都會(huì)導(dǎo)致下面這個(gè)簡(jiǎn)單的創(chuàng)建線程的內(nèi)核調(diào)用出現(xiàn)卡頓:

libsystem_kernel.dylib __workq_kernreturn

所以解決辦法只能是自己分析各 thread 的 call stack,根據(jù)用戶場(chǎng)景分析當(dāng)前正在消耗的系統(tǒng)資源。后面也確實(shí)通過最近提交的代碼分析,發(fā)現(xiàn)是由于增加了一些非常耗時(shí)的磁盤 io 任務(wù)(雖然也是放在在子線程),才出現(xiàn)這個(gè)看著不怎么沾邊的 call stack。revert 之后卡頓警報(bào)就消失了。

信息二

現(xiàn)有的卡頓檢測(cè)工具都只能在超時(shí)的情況下 dump call stack,但出現(xiàn)超時(shí)有可能是任務(wù) A,B,C 共同作用導(dǎo)致的,A 和 B 可能是真正耗時(shí)的任務(wù),C 不耗時(shí)但碰巧是最后一個(gè),所以被當(dāng)成元兇,而 A 和 B 卻沒有出現(xiàn)在上報(bào)日志里。我暫時(shí)也沒有想到特別好的解決辦法。很明顯,libsystem_kernel.dylib __workq_kernreturn 就是一個(gè)不怎么耗時(shí)的 C 任務(wù)。

信息三

在使用 GCD 創(chuàng)建 queue,或者說一個(gè) App 內(nèi)部使用 GCD 執(zhí)行子線程任務(wù)時(shí),最好有一套 App 所有團(tuán)隊(duì)都能遵循的隊(duì)列使用機(jī)制,避免創(chuàng)建過多的 thread,而出現(xiàn)意料之外的線程資源緊缺,代碼無(wú)法及時(shí)執(zhí)行的情況。這很難,尤其是在大公司動(dòng)則上百人的團(tuán)隊(duì)里面。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“iOS App使用GCD導(dǎo)致的卡頓現(xiàn)象怎么辦”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián)建站,關(guān)注創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)建站vcdvsql.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。

當(dāng)前標(biāo)題:iOSApp使用GCD導(dǎo)致的卡頓現(xiàn)象怎么辦-創(chuàng)新互聯(lián)
URL網(wǎng)址:http://vcdvsql.cn/article42/djpehc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、外貿(mào)建站、定制網(wǎng)站服務(wù)器托管響應(yīng)式網(wǎng)站、微信小程序

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

綿陽(yáng)服務(wù)器托管