① ios load方法調用順序
1.先調用類的 load 方法,先編譯哪個類就先調用該類的 load.
2.在調用 load 之前調用父類 load 方法.
3.分類 load 方法不會覆蓋本類的 load 方法.
4.initialize 方法先初始化父類,之後再初始化子類.
5.如果子類未實現 initialize 方法,就會調用父類的 initialize 方法.
6.如果分類實現了 initialize 方法,會覆蓋本類 initialize 方法.
load 函數是當類或分類(Category)被載入到 Objective-C runtime 時(就是被引用的時候)被調用的,實現這個方法可以讓我們在類載入的時候執行一些類相關的行為。當類被引用進項目的時候就會執行 load 函數(在 main 函數開始執行之前),與這個類是否被用到無關,每個類的 load 函數只會自動調用一次。load 函數調用特點如下:
1、當父類和子類都實現 load 函數時,二者的 load 方法都會被調用,父類的 load 方法執行順序要優先於子類。
2、當子類未實現 load 方法時,在載入該子類時,不會去調用其父類 load 方法。
3、類中的 load 方法執行順序要優先於類別(Category)。
4、當有多個類別(Category)都實現了 load 方法,這幾個 load 方法都會執行,但執行順序與編譯順序一致,即與類別在 Compile Sources 中出現的順序一致。
5、當有多個不同的類的時候,每個類 load 執行順序與編譯順序一致,即與其在 Compile Sources 出現的順序一致。
initialize 函數是在類或者其子類的收到第一條消息之前調用。這里所指的消息包括實例方法和類方法的調用。也就是說 initialize 方法是以懶載入的方式被調用的,如果程序一直沒有給某個類或它的子咐顫困類發送消息,那麼這個類的 initialize 方法是永遠不會被調用的。
1、父類的 initialize 方法會比子類先執行。
2、當子類未實現 initialize 方法時,在該子類收到第一條消息之前,會調用父類 initialize 方法,子類實現 initialize 方法時,則衡念會覆蓋父類 initialize 方法。有點多態的意思。
3、當有多個 Category 都實現了 initialize 方法,會覆蓋類中的方法,只執行最後那個被編譯洞團的,即 Compile Sources 列表中最後一個 Category 的 initialize 方法。
對於 load 和 initialize 方法,我們不要顯示的調用 super 的對應方法。
② 高並發,你真的理解透徹了嗎
高並發,幾乎是每個程序員都想擁有的經驗。原因很簡單:隨著流量變大,會遇到各種各樣的技術問題,比如介面響應超時、CPU load升高、GC頻繁、死鎖、大數據量存儲等等,這些問題能推動我們在技術深度上不斷精進。
在過往的面試中,如果候選人做過高並發的項目,我通常會讓對方談談對於高並發的理解,但是能系統性地回答好此問題的人並不多。
大概分成這樣幾類:
1、對數據化的指標沒有概念 :不清楚選擇什麼樣的指標來衡量高並發系統?分不清並發量和QPS,甚至不知道自己系統的總用戶量、活躍用戶量,平峰和高峰時的QPS和TPS等關鍵數據。
3、理解片面,把高並發設計等同於性能優化 :大談並發編程、多級緩存、非同步化、水平擴容,卻忽視高可用設計、服務治理和運維保障。
4、掌握大方案,卻忽視最基本的東西 :能講清楚垂直分層、水平分區、緩存等大思路,卻沒意識去分析數據結構是否合理,演算法是否高效,沒想過從最根本的IO和計算兩個維度去做細節優化。
這篇文章,我想結合自己的高並發項目經驗,系統性地總結下高並發需要掌握的知識和實踐思路,希望對你有所幫助。內容分成以下3個部分:
高並發意味著大流量,需要運用技術手段抵抗流量的沖擊,這些手段好比操作流量,能讓流量更平穩地被系統所處理,帶給用戶更好的體驗。
我們常見的高並發場景有:淘寶的雙11、春運時的搶票、微博大V的熱點新聞等。除了這些典型事情,每秒幾十萬請求的秒殺系統、每天千萬級的訂單系統、每天億級日活的信息流系統等,都可以歸為高並發。
很顯然,上面談到的高並發場景,並發量各不相同, 那到底多大並發才算高並發呢?
1、不能只看數字,要看具體的業務場景。不能說10W QPS的秒殺是高並發,而1W QPS的信息流就不是高並發。信息流場景涉及復雜的推薦模型和各種人工策略,它的業務邏輯可能比秒殺場景復雜10倍不止。因此,不在同一個維度,沒有任何比較意義。
2、業務都是從0到1做起來的,並發量和QPS只是參考指標,最重要的是:在業務量逐漸變成原來的10倍、100倍的過程中,你是否用到了高並發的處理方法去演進你的系統,從架構設計、編碼實現、甚至產品方案等維度去預防和解決高並發引起的問題?而不是一味的升級硬體、加機器做水平擴展。
此外,各個高並發場景的業務特點完全不同:有讀多寫少的信息流場景、有讀多寫多的交易場景, 那是否有通用的技術方案解決不同場景的高並發問題呢?
我覺得大的思路可以借鑒,別人的方案也可以參考,但是真正落地過程中,細節上還會有無數的坑。另外,由於軟硬體環境、技術棧、以及產品邏輯都沒法做到完全一致,這些都會導致同樣的業務場景,就算用相同的技術方案也會面臨不同的問題,這些坑還得一個個趟。
因此,這篇文章我會將重點放在基礎知識、通用思路、和我曾經實踐過的有效經驗上,希望讓你對高並發有更深的理解。
先搞清楚高並發系統設計的目標,在此基礎上再討論設計方案和實踐經驗才有意義和針對性。
高並發絕不意味著只追求高性能,這是很多人片面的理解。從宏觀角度看,高並發系統設計的目標有三個:高性能、高可用,以及高可擴展。
1、高性能:性能體現了系統的並行處理能力,在有限的硬體投入下,提高性能意味著節省成本。同時,性能也反映了用戶體驗,響應時間分別是100毫秒和1秒,給用戶的感受是完全不同的。
2、高可用:表示系統可以正常服務的時間。一個全年不停機、無故障;另一個隔三差五齣線上事故、宕機,用戶肯定選擇前者。另外,如果系統只能做到90%可用,也會大大拖累業務。
3、高擴展:表示系統的擴展能力,流量高峰時能否在短時間內完成擴容,更平穩地承接峰值流量,比如雙11活動、明星離婚等熱點事件。
這3個目標是需要通盤考慮的,因為它們互相關聯、甚至也會相互影響。
比如說:考慮系統的擴展能力,你會將服務設計成無狀態的,這種集群設計保證了高擴展性,其實也間接提升了系統的性能和可用性。
再比如說:為了保證可用性,通常會對服務介面進行超時設置,以防大量線程阻塞在慢請求上造成系統雪崩,那超時時間設置成多少合理呢?一般,我們會參考依賴服務的性能表現進行設置。
再從微觀角度來看,高性能、高可用和高擴展又有哪些具體的指標來衡量?為什麼會選擇這些指標呢?
2.2.1 性能指標
通過性能指標可以度量目前存在的性能問題,同時作為性能優化的評估依據。一般來說,會採用一段時間內的介面響應時間作為指標。
1、平均響應時間:最常用,但是缺陷很明顯,對於慢請求不敏感。比如1萬次請求,其中9900次是1ms,100次是100ms,則平均響應時間為1.99ms,雖然平均耗時僅增加了0.99ms,但是1%請求的響應時間已經增加了100倍。
2、TP90、TP99等分位值:將響應時間按照從小到大排序,TP90表示排在第90分位的響應時間, 分位值越大,對慢請求越敏感。
3、吞吐量:和響應時間呈反比,比如響應時間是1ms,則吞吐量為每秒1000次。
通常,設定性能目標時會兼顧吞吐量和響應時間,比如這樣表述:在每秒1萬次請求下,AVG控制在50ms以下,TP99控制在100ms以下。對於高並發系統,AVG和TP分位值必須同時要考慮。
另外,從用戶體驗角度來看,200毫秒被認為是第一個分界點,用戶感覺不到延遲,1秒是第二個分界點,用戶能感受到延遲,但是可以接受。
因此,對於一個 健康 的高並發系統,TP99應該控制在200毫秒以內,TP999或者TP9999應該控制在1秒以內。
2.2.2 可用性指標
高可用性是指系統具有較高的無故障運行能力,可用性 = 正常運行時間 / 系統總運行時間,一般使用幾個9來描述系統的可用性。
對於高並發系統來說,最基本的要求是:保證3個9或者4個9。原因很簡單,如果你只能做到2個9,意味著有1%的故障時間,像一些大公司每年動輒千億以上的GMV或者收入,1%就是10億級別的業務影響。
2.2.3 可擴展性指標
面對突發流量,不可能臨時改造架構,最快的方式就是增加機器來線性提高系統的處理能力。
對於業務集群或者基礎組件來說,擴展性 = 性能提升比例 / 機器增加比例,理想的擴展能力是:資源增加幾倍,性能提升幾倍。通常來說,擴展能力要維持在70%以上。
但是從高並發系統的整體架構角度來看,擴展的目標不僅僅是把服務設計成無狀態就行了,因為當流量增加10倍,業務服務可以快速擴容10倍,但是資料庫可能就成為了新的瓶頸。
像MySQL這種有狀態的存儲服務通常是擴展的技術難點,如果架構上沒提前做好規劃(垂直和水平拆分),就會涉及到大量數據的遷移。
因此,高擴展性需要考慮:服務集群、資料庫、緩存和消息隊列等中間件、負載均衡、帶寬、依賴的第三方等,當並發達到某一個量級後,上述每個因素都可能成為擴展的瓶頸點。
了解了高並發設計的3大目標後,再系統性總結下高並發的設計方案,會從以下兩部分展開:先總結下通用的設計方法,然後再圍繞高性能、高可用、高擴展分別給出具體的實踐方案。
通用的設計方法主要是從「縱向」和「橫向」兩個維度出發,俗稱高並發處理的兩板斧:縱向擴展和橫向擴展。
3.1.1 縱向擴展(scale-up)
它的目標是提升單機的處理能力,方案又包括:
1、提升單機的硬體性能:通過增加內存、 CPU核數、存儲容量、或者將磁碟 升級成SSD 等堆硬體的方式來提升。
2、提升單機的軟體性能:使用緩存減少IO次數,使用並發或者非同步的方式增加吞吐量。
3.1.2 橫向擴展(scale-out)
因為單機性能總會存在極限,所以最終還需要引入橫向擴展,通過集群部署以進一步提高並發處理能力,又包括以下2個方向:
1、做好分層架構:這是橫向擴展的提前,因為高並發系統往往業務復雜,通過分層處理可以簡化復雜問題,更容易做到橫向擴展。
上面這種圖是互聯網最常見的分層架構,當然真實的高並發系統架構會在此基礎上進一步完善。比如會做動靜分離並引入CDN,反向代理層可以是LVS+Nginx,Web層可以是統一的API網關,業務服務層可進一步按垂直業務做微服務化,存儲層可以是各種異構資料庫。
2、各層進行水平擴展:無狀態水平擴容,有狀態做分片路由。業務集群通常能設計成無狀態的,而資料庫和緩存往往是有狀態的,因此需要設計分區鍵做好存儲分片,當然也可以通過主從同步、讀寫分離的方案提升讀性能。
下面再結合我的個人經驗,針對高性能、高可用、高擴展3個方面,總結下可落地的實踐方案。
3.2.1 高性能的實踐方案
1、集群部署,通過負載均衡減輕單機壓力。
2、多級緩存,包括靜態數據使用CDN、本地緩存、分布式緩存等,以及對緩存場景中的熱點key、緩存穿透、緩存並發、數據一致性等問題的處理。
3、分庫分表和索引優化,以及藉助搜索引擎解決復雜查詢問題。
4、考慮NoSQL資料庫的使用,比如HBase、TiDB等,但是團隊必須熟悉這些組件,且有較強的運維能力。
5、非同步化,將次要流程通過多線程、MQ、甚至延時任務進行非同步處理。
6、限流,需要先考慮業務是否允許限流(比如秒殺場景是允許的),包括前端限流、Nginx接入層的限流、服務端的限流。
7、對流量進行 削峰填谷 ,通過 MQ承接流量。
8、並發處理,通過多線程將串列邏輯並行化。
9、預計算,比如搶紅包場景,可以提前計算好紅包金額緩存起來,發紅包時直接使用即可。
10、 緩存預熱 ,通過非同步 任務 提前 預熱數據到本地緩存或者分布式緩存中。
11、減少IO次數,比如資料庫和緩存的批量讀寫、RPC的批量介面支持、或者通過冗餘數據的方式幹掉RPC調用。
12、減少IO時的數據包大小,包括採用輕量級的通信協議、合適的數據結構、去掉介面中的多餘欄位、減少緩存key的大小、壓縮緩存value等。
13、程序邏輯優化,比如將大概率阻斷執行流程的判斷邏輯前置、For循環的計算邏輯優化,或者採用更高效的演算法。
14、各種池化技術的使用和池大小的設置,包括HTTP請求池、線程池(考慮CPU密集型還是IO密集型設置核心參數)、資料庫和Redis連接池等。
15、JVM優化,包括新生代和老年代的大小、GC演算法的選擇等,盡可能減少GC頻率和耗時。
16、鎖選擇,讀多寫少的場景用樂觀鎖,或者考慮通過分段鎖的方式減少鎖沖突。
上述方案無外乎從計算和 IO 兩個維度考慮所有可能的優化點,需要有配套的監控系統實時了解當前的性能表現,並支撐你進行性能瓶頸分析,然後再遵循二八原則,抓主要矛盾進行優化。
3.2.2 高可用的實踐方案
1、對等節點的故障轉移,Nginx和服務治理框架均支持一個節點失敗後訪問另一個節點。
2、非對等節點的故障轉移,通過心跳檢測並實施主備切換(比如redis的哨兵模式或者集群模式、MySQL的主從切換等)。
3、介面層面的超時設置、重試策略和冪等設計。
4、降級處理:保證核心服務,犧牲非核心服務,必要時進行熔斷;或者核心鏈路出問題時,有備選鏈路。
5、限流處理:對超過系統處理能力的請求直接拒絕或者返回錯誤碼。
6、MQ場景的消息可靠性保證,包括procer端的重試機制、broker側的持久化、consumer端的ack機制等。
7、灰度發布,能支持按機器維度進行小流量部署,觀察系統日誌和業務指標,等運行平穩後再推全量。
8、監控報警:全方位的監控體系,包括最基礎的CPU、內存、磁碟、網路的監控,以及Web伺服器、JVM、資料庫、各類中間件的監控和業務指標的監控。
9、災備演練:類似當前的「混沌工程」,對系統進行一些破壞性手段,觀察局部故障是否會引起可用性問題。
高可用的方案主要從冗餘、取捨、系統運維3個方向考慮,同時需要有配套的值班機制和故障處理流程,當出現線上問題時,可及時跟進處理。
3.2.3 高擴展的實踐方案
1、合理的分層架構:比如上面談到的互聯網最常見的分層架構,另外還能進一步按照數據訪問層、業務邏輯層對微服務做更細粒度的分層(但是需要評估性能,會存在網路多一跳的情況)。
2、存儲層的拆分:按照業務維度做垂直拆分、按照數據特徵維度進一步做水平拆分(分庫分表)。
3、業務層的拆分:最常見的是按照業務維度拆(比如電商場景的商品服務、訂單服務等),也可以按照核心介面和非核心介面拆,還可以按照請求源拆(比如To C和To B,APP和H5 )。
高並發確實是一個復雜且系統性的問題,由於篇幅有限,諸如分布式Trace、全鏈路壓測、柔性事務都是要考慮的技術點。另外,如果業務場景不同,高並發的落地方案也會存在差異,但是總體的設計思路和可借鑒的方案基本類似。
高並發設計同樣要秉承架構設計的3個原則:簡單、合適和演進。"過早的優化是萬惡之源",不能脫離業務的實際情況,更不要過度設計,合適的方案就是最完美的。
作者簡介:985碩士,前亞馬遜工程師,現大廠技術管理者。
③ 監控CPU和load飆升說明什麼
CPU過枯李載。
1、內存(條)太小導致CPU和load飆升。
2、型敗清音效卡的「緩存」太小導致CPU和load飆升。以上是監控CPU和卜前load飆升的原因。
④ keil5 load 不能用,編譯完程序load一直顯示灰色怎麼辦
把debug設置成軟體模擬了,改為jlink或你使用的工具就好了。
拓展:
1、編譯(compilation , compile) 1.利用編譯程序從源語言編寫的源程序產生目標程序的過程。 2.用編譯程序產生目標程序的動作。 編譯就是把高級語言變成計算機可以識別的2進制語言,計算機只認識1和0,編譯程序把人們熟悉的語言換成2進制的。 編譯程序把一個源程序翻譯純蔽豎成目標程序的工作過程分為五做大個階段:詞法分析;語並唯法分析;語義檢查和中間代碼生成;代碼優化;目標代碼生成。
2、編譯語言是一種以編譯器來實現的編程語言。它不像直譯語言一樣,由解釋器將代碼一句一句運行,而是以編譯器,先將代碼編譯為機器碼,再加以運行。理論上,任何編程語言都可以是編譯式,或直譯式的。它們之間的區別,僅與程序的應用有關。主要是進行詞法分析和語法分析,又稱為源程序分析,分析過程中發現有語法錯誤,給出提示信息。
⑤ 有關c語言結構體的初始化報錯
函數范圍一旅空個結構體對象Load;
但是你的返回的load的類型是Load load[];是一個拆斗瞎數組,或者說是一個指針。銷手
可以把函數返回改成: Load* Input(Load load[], int n);
⑥ Linux 突然很佔cpu load average 很高!!!
1、先使用top看下CPU佔用高的進程,找出進程的進程ID(pid);
查看方法:top
2、根友拆據進程ID(pid)查看是進程的那些線程佔用CPU高。
查看方法:top -Hp pid
3、使用pstack,查看CPU佔用高的線程在干什麼。
查看方法:pstack pid
4、根據pstack分析改晌,應該可以看出問題好殲棗所在。