多線程-概述及底層實(shí)現(xiàn)機(jī)制淺析

Paste_Image.png

前言

在打算寫這篇多線層底層實(shí)現(xiàn)機(jī)制的時(shí)候,突然發(fā)現(xiàn)自己對(duì)于計(jì)算機(jī)竟然懂得這么表面赁濒,對(duì)于CPU的工作原理都不完全清楚轨奄,于是又轉(zhuǎn)頭查看了一些CPU相關(guān)的資料。也不敢鉆的太深拒炎,怕自己迷路...挪拟,其中如有錯(cuò)誤,望知道的朋友在下面留言評(píng)論击你,我會(huì)及時(shí)更新的舞丛。


關(guān)于CPU

CPU(中央處理器)顧名思義是電腦中處理器的總部(電腦里幾個(gè)重要的硬件都自帶的有自己的處理器,比如果漾,GPU是顯卡自己的處理器等)球切,負(fù)責(zé)整個(gè)電腦的運(yùn)行調(diào)度。它是指揮者绒障,所以最底層的一些工作并不是由CPU來(lái)完成的吨凑。CPU以及高的速度再運(yùn)轉(zhuǎn),它的運(yùn)行是由一串串?dāng)?shù)字脈沖信號(hào)通過(guò)硅晶版上的晶體管實(shí)現(xiàn)的户辱,那一波波的數(shù)字脈沖信號(hào)震蕩的速度鸵钝,就是CPU那傳說(shuō)中的主頻

CPU的主頻與CPU實(shí)際的運(yùn)算能力并沒有直接關(guān)系庐镐。如今的CPU工藝先進(jìn)恩商,運(yùn)算流水線短,其主頻的高低在一定意義上又可以體現(xiàn)CPU性能的高低必逆。CPU的主頻不代表CPU的速度怠堪,但提高主頻對(duì)于提高CPU運(yùn)算速度卻是至關(guān)重要的。

關(guān)于CPU使用率名眉,其實(shí)就是你運(yùn)行的程序占用的CPU資源粟矿,表示你的機(jī)器在某個(gè)時(shí)間點(diǎn)的運(yùn)行程序的情況。使用率越高损拢,說(shuō)明你的機(jī)器在這個(gè)時(shí)間上運(yùn)行了很多程序陌粹,反之較少。使用率的高低與你的CPU強(qiáng)弱有直接關(guān)系福压。現(xiàn)代分時(shí)多任務(wù)操作系統(tǒng)對(duì) CPU 都是分時(shí)間片使用的:比如A進(jìn)程占用10ms掏秩,然后B進(jìn)程占用30ms或舞,然后空閑60ms,再又是A進(jìn)程占10ms蒙幻,B進(jìn)程占30ms映凳,空閑60ms;如果在一段時(shí)間內(nèi)都是如此,那么這段時(shí)間內(nèi)的占用率為40%杆煞。CPU對(duì)線程的響應(yīng)并不是連續(xù)的魏宽,通常會(huì)在一段時(shí)間后自動(dòng)中斷線程腐泻。未響應(yīng)的線程增加决乎,就會(huì)不斷加大CPU的占用。

操作系統(tǒng)的設(shè)計(jì)派桩,可以歸結(jié)為三點(diǎn):

  • (1)以多進(jìn)程形式构诚,允許多個(gè)任務(wù)同時(shí)運(yùn)行;
  • (2)以多線程形式铆惑,允許單個(gè)任務(wù)分成不同的部分運(yùn)行范嘱;
  • (3)提供協(xié)調(diào)機(jī)制,一方面防止進(jìn)程之間和線程之間產(chǎn)生沖突员魏,另一方面允許進(jìn)程之間和線程之間共享資源丑蛤。
CPU型號(hào) CPU內(nèi)核信息
I3 雙核四線程
I5 雙核四線程
I5 四核四線程
I7 四核八線程
I7 六核十二線程

關(guān)于CPU的詳細(xì)介紹可以看這里

關(guān)于多核、多處理器撕阎、多線程

了解了CPU的工作機(jī)制受裹,我們?cè)賮?lái)分析一下CPU的多核、多處理器虏束,與多線程棉饶。也許有人會(huì)問:“了解這些有什么卵用”,其實(shí)在我看來(lái)镇匀,詳細(xì)了解這些硬件對(duì)于我們理解多線程技術(shù)的必要性和開展多線程編程都是很必要的照藻,可以提供宏觀的理論依據(jù)。

多核

CPU的性能主要靠提高核心工作頻率來(lái)提高汗侵,由于物理限制幸缕,不能把CPU的核心頻率無(wú)限提高,所以發(fā)展出來(lái)雙核心或多核心的CPU晰韵。相當(dāng)于在一枚處理器上集成多個(gè)完整的計(jì)算引擎(內(nèi)核)冀值,他們共享緩存,內(nèi)存宫屠,寄存器等列疗。

,是物理的浪蹂,幾核就是真的有幾個(gè)物理核心抵栈。線程就是英特爾的超線程技術(shù)告材。是在一個(gè)實(shí)體處理器中,提供兩個(gè)邏輯線程古劲。線程是虛擬的斥赋,不是真實(shí)存在的。但性能上产艾,會(huì)模擬真實(shí)的核疤剑。也就是說(shuō),雙核4線程闷堡,看起來(lái)很像4核隘膘,但比真實(shí)的4核4線程慢,卻比雙核雙線程快杠览。

手機(jī)多核其實(shí)應(yīng)該叫多CPU,將多個(gè)CPU芯片封裝起來(lái)處理不同的事情弯菊,你甚至可以戲稱為“膠水核心”,也就是被強(qiáng)行粘在一起的意思踱阿。在待機(jī)或者空閑的時(shí)候管钳,八核的手機(jī)也只能用到一到兩個(gè)核心。

而電腦則不同软舌,PC的多核處理器是指在一個(gè)處理器上集成了多個(gè)運(yùn)算核心才漆,通過(guò)相互配合、相互協(xié)作可以處理同一件事情佛点,是多個(gè)并行的個(gè)體封裝在了一起醇滥。用一句話概括,就是并行處理恋脚,雙核就是單車道變多車道
我們都知道智能手機(jī)都是有CPU的腺办,iPhone6使用的A8處理器是一款雙核處理器。

多處理器(多CPU)

多處理器系統(tǒng)是指包含兩臺(tái)或多臺(tái)功能相近的處理器(多CPU)糟描,處理器之間彼此可以交換數(shù)據(jù)怀喉,所有處理器共享內(nèi)存,I/O設(shè)備船响,控制器躬拢,及外部設(shè)備,整個(gè)硬件系統(tǒng)由統(tǒng)一的操作系統(tǒng)控制见间,在處理器和程序之間實(shí)現(xiàn)作業(yè)聊闯、任務(wù)、程序米诉、數(shù)組極其元素各級(jí)的全面并行菱蔬。目前主流的服務(wù)器架構(gòu),超級(jí)計(jì)算機(jī)等等,都是多CPU多核架構(gòu)拴泌。

多線程

多線程是為了使得多個(gè)線程并行的工作以完成多項(xiàng)任務(wù)魏身,以提高系統(tǒng)的效率。線程是在同一時(shí)間需要完成多項(xiàng)任務(wù)的時(shí)候被實(shí)現(xiàn)
的蚪腐。

多線程實(shí)現(xiàn)的相關(guān)討論

下面進(jìn)入到正餐了箭昵,在討論多線程之前,我們需要先認(rèn)識(shí)一下回季,進(jìn)程家制、線程,以及相關(guān)值得注意的問題泡一。

什么是線程颤殴、進(jìn)程

來(lái)來(lái)來(lái),先讀一個(gè)有趣的故事《進(jìn)程與線程的一個(gè)簡(jiǎn)單解釋》,淺顯易懂,生動(dòng)形象地解釋了多項(xiàng)成相關(guān)的很多典型問題瘾杭。通過(guò)上文我們大致可以宏觀了解這些問題了诅病。

進(jìn)程: 進(jìn)程是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng)哪亿,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位粥烁,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)。進(jìn)程是計(jì)算機(jī)中已運(yùn)行程序的實(shí)體蝇棉。其本身并不是幾部運(yùn)行單位讨阻,是線程的容器。
線程: 線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位篡殷。線程是一組指令的集合它被包含在進(jìn)程之中钝吮,是進(jìn)程中的實(shí)際運(yùn)作單位。一條線程指的是進(jìn)程中一個(gè)單一順序的控制流板辽,一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程奇瘦,每條線程并行執(zhí)行不同的任務(wù)。線程是獨(dú)立調(diào)度和分派的基本單位劲弦。同一進(jìn)程中的多條線程將共享該進(jìn)程中的全部系統(tǒng)資源耳标,但是自有調(diào)用堆棧和寄存器環(huán)境。

線程邑跪、進(jìn)程的不同

主線程在程序中的地位和其他線程不同次坡,它是其他線程最終的父線程,且所有界面的顯示操作即AppKit或 UIKit的操作必須在主線程進(jìn)行画畅。

進(jìn)程和線程都是操作系統(tǒng)的概念砸琅。進(jìn)程是應(yīng)用程序的執(zhí)行實(shí)例,每個(gè)進(jìn)程是由私有的虛擬地址空間轴踱、代碼症脂、數(shù)據(jù)和其它各種系統(tǒng)資源組成。

線程和進(jìn)程十分相似,不同的只是線程比進(jìn)程小诱篷。首先沸版,線程采用了多個(gè)線程可共享資源的設(shè)計(jì)思想;例如兴蒸,它們的操作大部分都是在同一地址空間進(jìn)行的视粮。其次,從一個(gè)線程切換到另一線程所花費(fèi)的代價(jià)比進(jìn)程低橙凳。再次蕾殴,進(jìn)程本身的信息在內(nèi)存中占用的空間比線程大,因此線程更能允分地利用內(nèi)存岛啸。

線程是進(jìn)程的一部分
CPU調(diào)度的是線程
系統(tǒng)為進(jìn)程分配資源钓觉,不對(duì)線程分配資源

進(jìn)程和線程的關(guān)系:

一個(gè)線程只能屬于一個(gè)進(jìn)程,而一個(gè)進(jìn)程可以有多個(gè)線程坚踩,但至少有一個(gè)線程荡灾。 資源分配給進(jìn)程,同一進(jìn)程的所有線程共享該進(jìn)程的所有資源瞬铸。 處理機(jī)分給線程批幌,即真正在處理機(jī)上運(yùn)行的是線程。 線程在執(zhí)行過(guò)程中嗓节,需要協(xié)作同步荧缘。不同進(jìn)程的線程間要利用消息通信的辦法實(shí)現(xiàn)同步。

為什么要實(shí)現(xiàn)多線程

多線程技術(shù)的出現(xiàn)拦宣,主要是因?yàn)槎嗳蝿?wù)的需要截粗,比如我想同時(shí)寫文章和聽歌,如果我們的CPU一直被寫文章的任務(wù)占著鸵隧,等寫文章的任務(wù)結(jié)束后绸罗,再播放歌曲,很顯然達(dá)不到需要的“同時(shí)”做兩件事的效果豆瘫。

多線程的出現(xiàn)也是多核CPU珊蟀、多處理器計(jì)算機(jī)普及的需要,這樣可以提高CPU的利用率靡羡,增加并發(fā)性系洛,提高程序的執(zhí)行效率,更快的處理完任務(wù)略步。

在一些等待的任務(wù)實(shí)現(xiàn)上如用戶輸入描扯、文件讀寫和網(wǎng)絡(luò)收發(fā)數(shù)據(jù)等,線程就比較游泳了趟薄。在這種情況下我們可以釋放一些珍貴的資源如內(nèi)存占用等等绽诚。

多線程為何能實(shí)現(xiàn)

單就一個(gè)CPU而言兩個(gè)線程可以解決線程阻塞造成的不流暢問題,其本身運(yùn)行效率并沒有提高,多CPU的并行運(yùn)算才真正解決了運(yùn)行效率問題恩够,這也正是并發(fā)和并行的區(qū)別卒落。當(dāng)然,不管是多核還是單核開發(fā)人員不用過(guò)多的擔(dān)心蜂桶,因?yàn)槿蝿?wù)具體分配給幾個(gè)CPU運(yùn)算是由系統(tǒng)調(diào)度的儡毕,開發(fā)人員不用過(guò)多關(guān)心系統(tǒng)有幾個(gè)CPU。開發(fā)人員需要關(guān)心的是線程之間的依賴關(guān)系扑媚,因?yàn)橛行┎僮鞅仨氃谀硞€(gè)操作完成完才能執(zhí)行腰湾,如果不能保證這個(gè)順序勢(shì)必會(huì)造成程序問題。
每個(gè)線程被分配一個(gè)時(shí)間段疆股,稱作它的時(shí)間片费坊,即該進(jìn)程允許運(yùn)行的時(shí)間,使各個(gè)程序從表面上看是同時(shí)進(jìn)行的旬痹。如果在時(shí)間片結(jié)束時(shí)進(jìn)程還在運(yùn)行附井,則CPU將被剝奪并分配給另一個(gè)進(jìn)程。如果進(jìn)程在時(shí)間片結(jié)束前阻塞或結(jié)束两残,則CPU當(dāng)即進(jìn)行切換永毅。而不會(huì)造成CPU資源浪費(fèi)。在宏觀上:我們可以同時(shí)打開多個(gè)應(yīng)用程序磕昼,每個(gè)程序并行不悖卷雕,同時(shí)運(yùn)行节猿。但在微觀上:由于只有一個(gè)CPU票从,一次只能處理程序要求的一部分,如何處理公平滨嘱,一種方法就是引入時(shí)間片峰鄙,每個(gè)程序輪流執(zhí)行。調(diào)度程序所要做的就是維護(hù)一張就緒進(jìn)程列表太雨,當(dāng)進(jìn)程用完它的時(shí)間片后吟榴,它被移到隊(duì)列的末尾。

每個(gè)進(jìn)程都有私有的虛擬地址空間囊扳,進(jìn)程的所有線程共享同一地址空間吩翻。每個(gè)線程被CPU分配一個(gè)時(shí)間片,一旦被激活锥咸,它正常運(yùn)行直到時(shí)間片耗盡并被掛起狭瞎,此時(shí),操作系統(tǒng)選擇另一個(gè)線程進(jìn)行運(yùn)行搏予。通過(guò)時(shí)間片輪轉(zhuǎn)熊锭,又出于各個(gè)時(shí)間片很小(20毫秒級(jí)),看起來(lái)就像多個(gè)線程同時(shí)在工作碗殷。實(shí)際上精绎,只有在多處理器系統(tǒng)上才是真正的在可得到的處理器上同時(shí)運(yùn)行多個(gè)線程。

從一個(gè)進(jìn)程切換到另一個(gè)進(jìn)程是需要一定時(shí)間的--保存和裝入寄存器值及內(nèi)存映像锌妻,更新各種表格和隊(duì)列等代乃。假如進(jìn)程切換(process switch) - 有時(shí)稱為上下文切換(context switch),需要5毫秒仿粹,再假設(shè)時(shí)間片設(shè)為20毫秒襟己,則在做完20毫秒有用的工作之后,CPU將花費(fèi)5毫秒來(lái)進(jìn)行進(jìn)程切換牍陌。CPU時(shí)間的20%被浪費(fèi)在了管理開銷上擎浴。

時(shí)間片設(shè)得太短會(huì)導(dǎo)致過(guò)多的進(jìn)程切換,降低了CPU效率毒涧;而設(shè)得太長(zhǎng)又可能引起對(duì)短的交互請(qǐng)求的響應(yīng)變差贮预。將時(shí)間片設(shè)為100毫秒通常是一個(gè)比較合理的折衷。

線程越多越好嗎

線程多了可以提高程序并行執(zhí)行的速度契讲,但是并不是越多越好仿吞。
其一,每個(gè)線程都要占用內(nèi)存捡偏,多線程就意味著更多的內(nèi)存資源被占用唤冈,開啟線程需要占用一定的內(nèi)存空間(默認(rèn)情況下,主線程占用1M银伟,子線程占用512KB)你虹,如果開啟大量的線程,會(huì)占用大量的內(nèi)存空間彤避,降低程序的性能傅物。
其二,從微觀上講琉预,一個(gè)cpu不是同時(shí)執(zhí)行兩個(gè)線程的董饰,他是輪流執(zhí)行的,所以線程太多圆米,cpu必須不斷的在各個(gè)線程間快回更換執(zhí)行卒暂,線程間的切換無(wú)意間消耗了許多時(shí)間,所以cpu有效利用率反而是下降的

開發(fā)中實(shí)現(xiàn)多線程的方案

Mach是第一個(gè)以多線程方式處理任務(wù)的系統(tǒng)娄帖,因此多線程的底層實(shí)現(xiàn)機(jī)制是基于Mach的線程也祠。
然后開發(fā)中很少用Mach級(jí)的線程,因?yàn)镸ach級(jí)的線程沒有提供多線程的基本特征块茁,線程之間是獨(dú)立的

多線程的方案有以下幾種

  • C語(yǔ)言的POSIX接口方案

    Pthreads定義了一套C語(yǔ)言的類型齿坷、函數(shù)與常量桂肌,它以pthread.h頭文件和一個(gè)線程庫(kù)實(shí)現(xiàn)。線程庫(kù)實(shí)行了POSIX線程標(biāo)準(zhǔn)通常稱為Pthreads永淌。POSIX線程具有很好的可移植性崎场,使用pthreads編寫的代碼可運(yùn)行于Solaris、FreeBSD遂蛀、Linux 等平臺(tái)谭跨,Windows平臺(tái)亦有pthreads-win32可供使用。而且你需要手動(dòng)處理線程的各個(gè)狀態(tài)的轉(zhuǎn)換即管理生命周期李滴,比如螃宙,這段代碼雖然創(chuàng)建了一個(gè)線程,還需要銷毀這個(gè)線程所坯。感興趣的朋友谆扎,或者說(shuō)想要自己實(shí)現(xiàn)一套多線程方案,從底層開始定制芹助,那么可以去搜一下相關(guān)資料研究一下堂湖。

  • OC的NSThread方案。是對(duì)POSIX thread的封裝
  • C語(yǔ)言的GCD接口方案(性能最好状土,代碼更精簡(jiǎn))无蜂。
  • OC的NSOperation和NSOperationQueue(基于GCD)方案。

小結(jié)

本文洋洋灑灑寫了好多看似跟多線程無(wú)關(guān)的東西蒙谓,其實(shí)我認(rèn)為這些對(duì)之后多線程的學(xué)習(xí)是有幫助的斥季,如果你認(rèn)真對(duì)了本文,相信你會(huì)對(duì)多線程有更深的理解累驮,作為多線程系列的開胃菜酣倾,本文到此就結(jié)束了,后續(xù)會(huì)陸續(xù)發(fā)布多線程相關(guān)的文章慰照,如有不對(duì)之處灶挟,還望觀看的朋友,在下面的評(píng)論區(qū)指出毒租,thanks.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市箱叁,隨后出現(xiàn)的幾起案子墅垮,更是在濱河造成了極大的恐慌,老刑警劉巖耕漱,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件算色,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡螟够,警方通過(guò)查閱死者的電腦和手機(jī)灾梦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門峡钓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人若河,你說(shuō)我怎么就攤上這事能岩。” “怎么了萧福?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵拉鹃,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我鲫忍,道長(zhǎng)膏燕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任悟民,我火速辦了婚禮坝辫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘射亏。我一直安慰自己阀溶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布银锻。 她就那樣靜靜地躺著,像睡著了一般击纬。 火紅的嫁衣襯著肌膚如雪更振。 梳的紋絲不亂的頭發(fā)上饭尝,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天实撒,我揣著相機(jī)與錄音涉瘾,去河邊找鬼立叛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛其做,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播驹沿,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼浮庐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼审残!你這毒婦竟也來(lái)了搅轿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎幻工,沒想到半個(gè)月后黎茎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體傅瞻,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嗅骄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年慕爬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了儿惫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡更胖,死狀恐怖隔显,靈堂內(nèi)的尸體忽然破棺而出括眠,到底是詐尸還是另有隱情倍权,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布当船,位于F島的核電站德频,受9級(jí)特大地震影響壹置,放射性物質(zhì)發(fā)生泄漏表谊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望步藕。 院中可真熱鬧挑格,春花似錦漂彤、人聲如沸挫望。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)破讨。三九已至提陶,卻和暖如春隙笆,著一層夾襖步出監(jiān)牢的瞬間锌蓄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工撑柔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘸爽,地道東北人醉锄。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓攀甚,卻偏偏與公主長(zhǎng)得像夸赫,于是被迫代替她去往敵國(guó)和親车海。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蹬铺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容