《Objective-C高級(jí)編程》GCD

Snip20171213_30.png
1.1 什么是GCD

Grand Central Dispatch是異步執(zhí)行任務(wù)的技術(shù)之一停局。一般將應(yīng)用程序中記述的線程管理用的代碼在系統(tǒng)級(jí)中實(shí)現(xiàn)阵翎。開發(fā)者只需要定義想要執(zhí)行的任務(wù)并追加到適當(dāng)?shù)腄ispatch Queue中,GCD就能生成必要的線程并計(jì)劃執(zhí)行任務(wù)。由于線程管理是作為系統(tǒng)的一部分來實(shí)現(xiàn)的。隱藏可以統(tǒng)一管理模蜡。也可以執(zhí)行任務(wù)。這樣就比一切的線程更有效率扁凛。

1.2 多線程編程
線程
  • 一個(gè)CPU執(zhí)行的CPU命令列為一條無分叉路徑忍疾,即為“線程”
定理
  • 一個(gè)CPU核執(zhí)行的CPU命令列為一條無分叉路徑
  • 這種無分叉路徑不止一條,存在有多條時(shí)即為“多線程”谨朝。在多線程中卤妒,一個(gè)CPU核執(zhí)行多條不同路徑上的不同命令。


    Snip20171221_17.png
上下文切換

CPU的寄存器等信息保存到各自路徑專用的內(nèi)存塊中字币,從切換目標(biāo)路徑專用的內(nèi)存塊中则披,復(fù)原CPU寄存器等信息,繼續(xù)執(zhí)行切換路徑的CPU命令列洗出。這種被稱為“上下文切換”士复。

多線程編程

由于使用多線程的程序可以在某個(gè)線程和其他線程之間反復(fù)多次進(jìn)行上下文切換,因此看上去就好像1個(gè)CPU核能夠并列地執(zhí)行多個(gè)線程一樣翩活。而且在具有多個(gè)CPU核的情況下阱洪,就不是“看上去像了“便贵,而是真的提供了多個(gè)CPU核并行執(zhí)行多個(gè)線程的技術(shù)。

多線程編程實(shí)際上是一種易發(fā)生各種問題的編程技術(shù)冗荸。比如多個(gè)線程更新相同的資源會(huì)導(dǎo)致數(shù)據(jù)的不一致(數(shù)據(jù)競(jìng)爭)嫉沽,停止等待事件的線程會(huì)導(dǎo)致多個(gè)線程相互持續(xù)等待(死鎖),使用太多線程會(huì)消耗大量內(nèi)存等俏竞。

Snip20171221_18.png
多線程的優(yōu)點(diǎn)

弊端:應(yīng)用程序在啟動(dòng)時(shí),通過最先執(zhí)行的線程堂竟,即”主線程“來描述用戶界面魂毁,處理觸摸屏幕的事件等。如果在該主線程中進(jìn)行長時(shí)間的處理出嘹,如AR用畫像的識(shí)別貨數(shù)據(jù)庫訪問席楚,就會(huì)妨礙主線程的執(zhí)行(阻塞)。在OS X和iOS的應(yīng)用程序中税稼,會(huì)妨礙主線程中被稱為RunLoop的主循環(huán)執(zhí)行烦秩,從而導(dǎo)致不能更新用戶界面,應(yīng)用程序的畫面長時(shí)間停滯等問題郎仆。

這就是長時(shí)間的處理不在主線程中執(zhí)行而在其他線程中執(zhí)行的原因只祠。


Snip20171221_19.png

使用多線程編程,在執(zhí)行長時(shí)間的處理時(shí)間時(shí)仍可以保證用戶界面的響應(yīng)性能扰肌。

2. GCD的API

GCD的說明:開發(fā)者要做的只是定義想執(zhí)行的任務(wù)并追加到適當(dāng)?shù)腄ispatch Queue中抛寝。

2.1 Dispatch Queue

是執(zhí)行處理的等待隊(duì)列。應(yīng)用程序編程人員通過dispatch_async函數(shù)等API曙旭,在Block語法中記述想執(zhí)行的處理并將其追加到Dispatch Queue中盗舰。Dispatch Queue按照追加的順序(FIFO)執(zhí)行處理。

Snip20171222_21.png

在執(zhí)行處理時(shí)存在兩種Dispatch Queue桂躏,一種是等待現(xiàn)在執(zhí)行中處理的Serial Dispatch Queue钻趋,另一種是不等待現(xiàn)在執(zhí)行中處理的Concurrent Dispatch Queue。

Snip20171222_22.png
并行執(zhí)行

就是使用多個(gè)線程同時(shí)執(zhí)行多個(gè)處理

Snip20171222_23.png
2.2 dispatch_queue_create

通過dispatch_queue_create函數(shù)可生成Dispatch Queue剂习。

  • 多個(gè)Serial Dispatch Queue 可并行執(zhí)行


    Snip20171222_24.png

如果過多使用多線程蛮位,就會(huì)消耗大量內(nèi)存,引起大量的上下文切換鳞绕,大幅度降低系統(tǒng)的響應(yīng)性能土至。

  • 當(dāng)想并行執(zhí)行不發(fā)生數(shù)據(jù)競(jìng)爭等問題的處理時(shí),使用Concurrent Dispatch Queue猾昆。而且對(duì)于Concurrent Dispatch Queue來說陶因,不管生成多少。由于XNU內(nèi)核只使用有效管理的線程垂蜗,因此不會(huì)發(fā)生Serial Dispatch Queue的那些問題楷扬。
2.3 Main Dispatch Queue / Global Dispatch Queue

第二種方法是獲取系統(tǒng)標(biāo)準(zhǔn)提供的Dispatch Queue解幽。

  • Main Dispatch Queue
  1. 是在主線程中執(zhí)行的Dispatch Queue,因?yàn)橹骶€程只有一個(gè)烘苹,所以Main Dispatch Queue自然就是Serial Dispatch Queue串行隊(duì)列躲株。
  2. 追加到Main Dispatch Queue的處理在主線程的RunLoop中執(zhí)行。由于在主線程中執(zhí)行镣衡,因此要將用戶界面的界面更新等一些必須在主線程中執(zhí)行的處理追加到Main Dispatch使用霜定。


    Snip20171222_25.png
  • Global Dispatch Queue
  1. 另一個(gè)Global Dispatch Queue是所有應(yīng)用程序都能夠使用的Concurrent Dispatch Queue。沒有必要通過dispatch_queue_create函數(shù)逐個(gè)生成Concurrent Dispatch Queue廊鸥。只要獲取Global Dispatch Queue使用即可望浩。
  2. Global Dispatch Queue有四個(gè)優(yōu)先級(jí),分別是高優(yōu)先級(jí)(High Priority)惰说,默認(rèn)優(yōu)先級(jí)(Default Priority)磨德,低優(yōu)先級(jí)(Low Priority)和后臺(tái)優(yōu)先級(jí)(Background Priority)。

對(duì)于Main Dispatch Queue和Global Dispatch Queue執(zhí)行dispatch_retain函數(shù)和dispatch_release函數(shù)不會(huì)引起任何變化吆视,也不會(huì)有任何問題典挑。這也是獲取并使用Global Dispatch Queue比生成,使用啦吧,釋放Concurrent Dispatch Queue更輕松的原因您觉。

2.4 dispatch_set_target_queue

dispatch_queue_create函數(shù)生成的Dispatch Queue不管是Serial Dispatch Queue還是Concurrnet Dispatch Queue,都使用與默認(rèn)優(yōu)先級(jí)Global Dispatch Queue相同執(zhí)行優(yōu)先級(jí)的線程授滓。而變更生成的Dispatch Queue的執(zhí)行優(yōu)先級(jí)要使用dispatch_set_target_queue函數(shù)顾犹。

在必須將不可并行執(zhí)行的處理追加到多個(gè)Serial Dispatch Queue中時(shí),如果使用dispatch_set_target_queue函數(shù)將目標(biāo)指定為某一個(gè)Serial Dispatch Queue褒墨,即可防止處理并行執(zhí)行炫刷。

2.5 dispatch_after
  • dispatch_after函數(shù)并不是在指定時(shí)間后執(zhí)行處理,而只是在指定時(shí)間追加處理到Dispatch Queue郁妈,此源代碼與在3秒后用dispatch_async函數(shù)追加Block到Main Dispatch Queue的相同浑玛。
  • 因?yàn)镸ain Dispatch Queue在主線程的Runloop中執(zhí)行,所以在此比如每隔1/60秒執(zhí)行的Runloop中噩咪,Block最快在3秒后執(zhí)行顾彰,最慢在3秒+1/60秒后執(zhí)行,并且在Main Dispatch Queue有大量處理追加或主線程的處理本身有延時(shí)時(shí)胃碾,這個(gè)時(shí)間會(huì)更長涨享。
  • dispatch_time函數(shù)通常用于計(jì)算相對(duì)時(shí)間,而dispatch_walltime函數(shù)用于計(jì)算絕對(duì)時(shí)間仆百。
2.6 Dispatch Group

在追加到Dispatch Queue中的多個(gè)處理全部結(jié)束后想執(zhí)行結(jié)束處理的需求厕隧。

  • 向Global Dispatch Queue即Concurrent Dispatch Queue追加處理,多個(gè)線程并行執(zhí)行,所以追加處理的執(zhí)行順序不定吁讨。執(zhí)行時(shí)會(huì)發(fā)生變化髓迎,但是此執(zhí)行結(jié)束的done一定是最后輸出的。
  • 無論向什么樣的Dispatch Queue中追加處理建丧,使用Dispatch Group都可以監(jiān)聽這些處理執(zhí)行的結(jié)束排龄。一旦檢測(cè)到所有處理執(zhí)行結(jié)束,就可以將結(jié)束的處理追加到Dispatch Queue中翎朱,這就是使用Dispatch Group的原因橄维。
  • 在Dispatch Group中也可以使用dispatch_group_wait函數(shù)僅等待全部處理執(zhí)行結(jié)束。
2.7 dispatch_barrier_async

使用dispatch_barrier_async函數(shù)拴曲,dispatch_barrier_async函數(shù)會(huì)等待追加到Concurrent Dispatch Queue上的并行執(zhí)行的處理全部結(jié)束后争舞,再將指定的處理追加到改Concurrent Dispatch Queue中,然后再有dispatch_barrier_async函數(shù)追加的處理執(zhí)行完畢之后疗韵,Concurrent Dispatch Queue才恢復(fù)為一般的動(dòng)作,追加到該Concurrent Dispatch Queue的處理又開始并行執(zhí)行侄非。


Snip20171228_12.png

使用Concurrent Dispatch Queue和dispatch_barrier_async函數(shù)可實(shí)現(xiàn)高效的數(shù)據(jù)庫訪問和文件訪問蕉汪。

2.8 dispatch_sync

dispatch_async函數(shù)的“async”意味著“非同步”(asynchronous),就是將指定的Block“非同步”地追加到指定的Dispatch Queue中逞怨。dispatch_async函數(shù)不做任何等待者疤。


Snip20171228_13.png

dispatch_sync同步,(synchronous),即將指定的Block“同步”追加到指定的Dispatch Queue中叠赦。在追加Block結(jié)束之前驹马,dispatch_sync函數(shù)會(huì)一直等待。


Snip20171228_14.png

等待意味著當(dāng)前線程停止

一旦調(diào)用dispatch_sync函數(shù)除秀,那么在指定的處理執(zhí)行結(jié)束之前糯累,該函數(shù)不會(huì)返回。dispatch_sync函數(shù)可以簡化源代碼册踩,也可說是簡易版的dispatch_group_wait函數(shù)泳姐。
正因?yàn)閐ispatch_sync函數(shù)使用簡單,所以容易引起問題暂吉,即死鎖胖秒。

例如如果在主線程中執(zhí)行以下源代碼就會(huì)死鎖

dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
    NSLog(@"Hello?");
});

改源代碼在Main Dispatch Queue即主線程中執(zhí)行指定的Block,并等待其執(zhí)行結(jié)束慕的。而其實(shí)在主線程中正在執(zhí)行這些源代碼阎肝,所以無法執(zhí)行追加到Main Dispatch Queue的Block。
下面的例子也一樣

dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
    dispatch_sync(queue,^{
        NSLog(@"Hello?");
    });
});

Mian Dispatch Queue中執(zhí)行的Block等待Main Dispatch Queue中要執(zhí)行的Block執(zhí)行結(jié)束肮街。
當(dāng)然Serial Dispatch Queue 也會(huì)引起相同的問題风题。

dispatch_queue_t queue = dispatch_queue_create("com.example.gcd.MySerialDispatchQueue",NULL);
dispatch_async(queue, ^{
    dispatch_sync(queue, ^{
        NSLog(@"Hello?");
    });
});

另外,由Dispatch_barrier_async函數(shù)中含有async可推出出,相應(yīng)的也有dispatch_barrier_sync函數(shù)俯邓。dispatch_barrier_async函數(shù)的作用是在等待追加的處理全部執(zhí)行結(jié)束后骡楼,再追加處理到Dispatch Queue中,此外稽鞭,它還與dispatch_sync函數(shù)相同鸟整,會(huì)等待追加處理的執(zhí)行結(jié)束。

2.9 dispatch_apple

dispatch_apple函數(shù)是Dispatch_sync函數(shù)和Dispatch Group的關(guān)聯(lián)API朦蕴。該函數(shù)按指定的次數(shù)將指定的Block追加到指定的Dispatch Queue中篮条,并等待全部處理執(zhí)行結(jié)束。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t index) {
    NSLog(@"%zu",index);
});
NSLog(@"done");

結(jié)果如下:
1
2
3
0
4
5
6
7
8
9
done

因?yàn)樵贕lobal Dispatch Queue中執(zhí)行處理吩抓,所以各個(gè)處理的時(shí)間不定涉茧。但是輸出結(jié)果中最后的done必定在最后的位置上。這是因?yàn)閐ispatch_apple函數(shù)會(huì)等待全部處理執(zhí)行結(jié)束疹娶。

NSArray *array = @[@0,@1,@2,@3,@4];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply([array count], queue, ^(size_t index) {
    NSLog(@"%zu:%@",index,[array objectAtIndex:index]);
});
NSLog(@"done");

結(jié)果:
3:3
0:0
1:1
2:2
4:4
done

這樣可以簡單地在Global Dispatch Queue中對(duì)所有的元素執(zhí)行Block

另外伴栓,由于dispatch_apply函數(shù)也與dispatch_sync函數(shù)相同,會(huì)等待處理執(zhí)行結(jié)束雨饺,因此推薦在dispatch_async函數(shù)非同步地執(zhí)行dispatch_apply函數(shù)钳垮。

NSArray *array = @[@0,@1,@2,@3,@4];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 在Global Dispatch Queue中非同步執(zhí)行
dispatch_async(queue, ^{
    // 等待dispatch_apply函數(shù)中全部處理執(zhí)行結(jié)束
    dispatch_apply([array count], queue, ^(size_t index) {
        // 并列處理包含在NSArray對(duì)象的全部對(duì)象
        NSLog(@"%zu:%@",index,[array objectAtIndex:index]);
    });
    // dispatch_apply函數(shù)中的處理全部執(zhí)行結(jié)束
    // 在Main Dispatch Queue中非同步執(zhí)行
    dispatch_async(dispatch_get_main_queue(), ^{
        // 在Main Dispatch Queue中執(zhí)行處理用戶界面更新等等
        NSLog(@"done 界面刷新");
    });
});

執(zhí)行結(jié)果:
1:1
2:2
3:3
0:0
4:4
done 界面刷新
2.10 dispatch_suspend/dispatch_resume

當(dāng)追加大量處理到Dispatch Queue時(shí),在追加處理的過程中额港,有時(shí)希望不執(zhí)行已追加的處理饺窿。在這種情況下,只要掛起Dispatch Queue即可移斩。當(dāng)可以執(zhí)行時(shí)再恢復(fù)肚医。

  • dispatch_suspend函數(shù)掛起指定的Dispatch Queue
dispatch_suspend(queue);
  • Dispatch_resume函數(shù)恢復(fù)指定的Dispatch Queue
dispatch_resume(queue);

這些函數(shù)對(duì)已經(jīng)執(zhí)行的處理沒有影響。掛起后向瓷,追加到Dispatch Queue中但尚未執(zhí)行的處理在此之后停止執(zhí)行肠套。而恢復(fù)則使這些處理能夠繼續(xù)執(zhí)行。

2.11 Dispatch Semaphonre

如前所述猖任,當(dāng)并行執(zhí)行的處理更新數(shù)據(jù)時(shí)糠排,會(huì)產(chǎn)生數(shù)據(jù)不一致的情況,有時(shí)應(yīng)用程序還會(huì)導(dǎo)致異常結(jié)束超升。雖然使用Serial Dispatch Queue和disaptch_barrier_async函數(shù)可以避免這類問題入宦,但有必要進(jìn)行更細(xì)粒度的為他控制。
以下場(chǎng)景室琢,不考慮順序乾闰,將所有數(shù)據(jù)追加到NSMutableArray中。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray *array = [[NSMutableArray alloc] init];;
for (int i = 0; i < 100000; i++) {
    dispatch_async(queue, ^{
        [array addObject:[NSNumber numberWithInt:i]];
    });
}

因?yàn)樵撛创a使用Global Dispatch更新NSMutableArray類對(duì)象盈滴,所以執(zhí)行后由內(nèi)存錯(cuò)誤導(dǎo)致應(yīng)用程序異常結(jié)束的概率很高涯肩。此時(shí)應(yīng)使用Dispatch Semaphore轿钠。

  • Disaptch Semaphore
    Dispatch Semaphore是持有計(jì)數(shù)的信號(hào),該計(jì)數(shù)是多線程編程中的計(jì)數(shù)類型信號(hào)病苗。所謂信號(hào)疗垛,類似于過馬路時(shí)常用的手旗×螂可以通過時(shí)舉起手旗贷腕,不可通過時(shí)放下手旗。而在Dispatch Semaphore中咬展,使用計(jì)數(shù)來實(shí)現(xiàn)該功能泽裳。計(jì)數(shù)為零時(shí)等待,計(jì)數(shù)為1貨大于1時(shí)破婆,減去1而不等待涮总。

dispatch_semaphore_wait函數(shù)返回0時(shí),可安全地執(zhí)行需要進(jìn)行排他控制的處理祷舀。改處理結(jié)束時(shí)通過dispatch_semaphore_signal函數(shù)將Dispatch Semaphore額計(jì)數(shù)值加1.

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
// 生成dispatch Semaphore瀑梗,并且計(jì)數(shù)初始值設(shè)定為1.保證可訪問NSMutableArray類對(duì)象的線程同時(shí)只能有1個(gè)
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    
NSMutableArray *array = [[NSMutableArray alloc] init];
    
for (int i = 0; i < 100000; i++) {
    dispatch_async(queue, ^{
        // 等待Dispatch Semaphore,一直等待,直到Dispatch Semaphore的計(jì)數(shù)值達(dá)到大于等于1
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
        [array addObject:[NSNumber numberWithInt:i]];
            
        // 排他控制處理結(jié)束裳扯,通過dispatch_semaphore_signal函數(shù)將Dispatch Semaphore的計(jì)數(shù)值加1
        dispatch_semaphore_signal(semaphore);
    });
}

在沒有Serial Dispatch和dispatch_barrier_async函數(shù)那么大粒度并且一部分處理需要進(jìn)行排他控制的情況下抛丽,Dispatch Semaphore便可發(fā)揮威力.

2.12 dispatch_once

dispatch_once函數(shù)是保證在應(yīng)用程序中只執(zhí)行一次指定處理的API。

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    //初始化操作
});

通過dispatch_once函數(shù)嚎朽,該源代碼即使在多線程環(huán)境下執(zhí)行铺纽,也可以保證百分之百的安全柬帕。

2.13 Dispatch I/0

在讀取較大文件時(shí)哟忍,如果將文件分成合適的大小并使用Global Dispatch Queue并列讀取,會(huì)比一般的讀取速度快很多∠萸蓿現(xiàn)今的輸入/輸出硬件已經(jīng)可以做到一次使用多個(gè)線程更快地并列讀取了锅很。能實(shí)現(xiàn)這一功能的就是Dispatch I/0和Dispatch Data。

如果想提高文件讀取的速度凤跑,可以嘗試使用Dispatch I/O

3. GCD的實(shí)現(xiàn)
3.1 Dispatch Queue

GCD的Dispatch Que非常方便爆安,它是如何實(shí)現(xiàn)的呢?

  • 用于管理追加的Block得C語言層實(shí)現(xiàn)的FIFO隊(duì)列
  • Atomic函數(shù)中實(shí)現(xiàn)的用于排他控制的輕量級(jí)信號(hào)
  • 用于管理現(xiàn)場(chǎng)的C語言層實(shí)現(xiàn)的一些容器

通常仔引,應(yīng)用程序中編寫的線程管理用的代碼要在系統(tǒng)級(jí)實(shí)現(xiàn)

系統(tǒng)級(jí)即iOS和OS X的核心XNU內(nèi)核級(jí)上實(shí)現(xiàn)

3.2 Dispatch Source

GCD中除了注意的Dispatch Queue外扔仓,還有不太引人注目的Dispatch Source。它是BSD系內(nèi)核慣有功能kqueue的包裝咖耘。

Kqueue是在XNU內(nèi)核中發(fā)生各種事件時(shí)翘簇,在應(yīng)用編程方執(zhí)行處理的技術(shù)。其CPU負(fù)荷非常小儿倒,盡量不占用資源版保。kqueue可以說是應(yīng)用程序處理XNU內(nèi)核中發(fā)生的各種事件的方法中最優(yōu)秀的一種。

Dispatch Source與Dispatch Queue不同,是可以取消的彻犁。而且取消時(shí)必須執(zhí)行的處理可指定為調(diào)用的Block形式叫胁。因此使用Dispatch Source實(shí)現(xiàn)XNU內(nèi)核中發(fā)生的事件處理要比直接使用kqueue實(shí)現(xiàn)更為簡單。在必須使用kqueue的情況下希望大家還是使用Dispatch Source汞幢,它比較簡單驼鹅。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市急鳄,隨后出現(xiàn)的幾起案子谤民,更是在濱河造成了極大的恐慌,老刑警劉巖疾宏,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件张足,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡坎藐,警方通過查閱死者的電腦和手機(jī)为牍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岩馍,“玉大人碉咆,你說我怎么就攤上這事≈鳎” “怎么了疫铜?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長双谆。 經(jīng)常有香客問我壳咕,道長,這世上最難降的妖魔是什么顽馋? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任谓厘,我火速辦了婚禮,結(jié)果婚禮上寸谜,老公的妹妹穿的比我還像新娘竟稳。我一直安慰自己,他們只是感情好熊痴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布他爸。 她就那樣靜靜地躺著,像睡著了一般果善。 火紅的嫁衣襯著肌膚如雪诊笤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天岭埠,我揣著相機(jī)與錄音盏混,去河邊找鬼蔚鸥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛许赃,可吹牛的內(nèi)容都是我干的止喷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼混聊,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼弹谁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起句喜,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤预愤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后咳胃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體植康,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年展懈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了销睁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡存崖,死狀恐怖冻记,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情来惧,我是刑警寧澤冗栗,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站供搀,受9級(jí)特大地震影響隅居,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜趁曼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一军浆、第九天 我趴在偏房一處隱蔽的房頂上張望棕洋。 院中可真熱鬧挡闰,春花似錦、人聲如沸掰盘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愧捕。三九已至奢驯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間次绘,已是汗流浹背瘪阁。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工撒遣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人管跺。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓义黎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親豁跑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子廉涕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355