多個(gè)網(wǎng)絡(luò)請求ABC執(zhí)行完再執(zhí)行D的正確理解(GCD線程同步)

前言

我發(fā)現(xiàn)網(wǎng)絡(luò)上很多介紹多線程的案例感覺都是錯(cuò)誤的例子。也不能說錯(cuò)的,例如用異步并發(fā)隊(duì)列的時(shí)候,他們只是打印了一個(gè)log,這種打印的行為本身就是同步任務(wù),肯定按照最簡單的例子進(jìn)行打印了,看到的效果自然是很多文章所說的。但是如果你Block里面的任務(wù)是網(wǎng)絡(luò)請求呢?還能保證網(wǎng)絡(luò)異步任務(wù)的一致性?很顯然大部分文章壓根沒有考慮任務(wù)的異步性,而且顯示開發(fā)中大部分任務(wù)都是異步的,因此本文先從網(wǎng)上的同步任務(wù),也就是比較簡單的案例開始介紹,最后再通過一道阿里的面試題來引出實(shí)際開發(fā)中的問題,這個(gè)題目非常有代表性。

線程同步

同步異步并發(fā)串行什么的可以看看這個(gè)簡單的介紹

阿里有個(gè)面試題

使用GCD如何實(shí)現(xiàn)A,B,C三個(gè)任務(wù)并發(fā),完成后執(zhí)行任務(wù)D?

// 異步 并發(fā)隊(duì)列 當(dāng)前線程不等待,而且任務(wù)是并發(fā)隊(duì)列,一次可以執(zhí)行多個(gè)
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        // 第一種 同步任務(wù)
        NSLog(@"同步任務(wù)打印1");
        // 第二種 網(wǎng)絡(luò)請求發(fā)送任務(wù) (發(fā)送這個(gè)操作是任務(wù),而網(wǎng)絡(luò)返回的報(bào)文是不歸任務(wù)管理的,因此發(fā)送任務(wù)發(fā)送之后,任務(wù)已經(jīng)結(jié)束)
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"異步任務(wù)返回報(bào)文打印1");
        });
    });

可以看到異步并發(fā)任務(wù)有兩種,一種任務(wù)是同步的,一種任務(wù)是網(wǎng)絡(luò)請求,發(fā)送操作是同步的,但是請求到的結(jié)果是異步的。阿里的面試題,肯定是后者異步并發(fā)隊(duì)列里面的任務(wù)也是并發(fā)的操作,如何實(shí)現(xiàn)ABC三個(gè)網(wǎng)絡(luò)請求都回來之后->執(zhí)行D這樣的操作?

異步并發(fā)(同步任務(wù))

同步任務(wù)很簡單,也是所有你能搜到的資料告訴你如何做到的幾個(gè)方法。

第一種GCD group

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_async(group, queue, ^{
        NSLog(@"同步任務(wù)A");
    });

    dispatch_group_async(group, queue, ^{
        NSLog(@"同步任務(wù)B");
    });

    dispatch_group_async(group, queue, ^{
        NSLog(@"同步任務(wù)C");
    });

    dispatch_group_notify(group, queue, ^{
        NSLog(@"任務(wù)完成執(zhí)行");
    });
//    2018-04-18 10:18:52.950271+0800 GCD[2283:78081] 同步任務(wù)B
//    2018-04-18 10:18:52.950271+0800 GCD[2283:78082] 同步任務(wù)C
//    2018-04-18 10:18:52.950273+0800 GCD[2283:78083] 同步任務(wù)A
//    2018-04-18 10:18:52.950424+0800 GCD[2283:78082] 任務(wù)完成執(zhí)行

//    2018-04-18 10:19:30.821003+0800 GCD[2315:79354] 同步任務(wù)B
//    2018-04-18 10:19:30.821003+0800 GCD[2315:79355] 同步任務(wù)A
//    2018-04-18 10:19:30.821003+0800 GCD[2315:79370] 同步任務(wù)C
//    2018-04-18 10:19:30.821145+0800 GCD[2315:79355] 任務(wù)完成執(zhí)行

可以看到,異步線程,并發(fā)隊(duì)列里面,三個(gè)任務(wù)可以同時(shí)執(zhí)行,因此打印順序隨機(jī)。但是由于打印的任務(wù),這個(gè)打印的動(dòng)作是同步的,沒有再開線程有其他進(jìn)一步的異步操作,所以你看起來好像沒什么問題。

第二種 dispatch_barrier_async

dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)A");
    });

    dispatch_async(queue, ^{
        NSLog(@"任務(wù)B");
    });

    dispatch_async(queue, ^{
        NSLog(@"任務(wù)C");
    });

    dispatch_barrier_async(queue, ^{
        NSLog(@"阻塞自定義并發(fā)隊(duì)列");
    });

    dispatch_async(queue, ^{
        NSLog(@"任務(wù)D");
    });

    dispatch_async(queue, ^{
        NSLog(@"任務(wù)E");
    });

注意,這里用到的dispatch_barrier_async如果使用的隊(duì)列是dispatch_global_queue,那么就等同意dispatch_async,起不到阻塞的作用。我們需要自己創(chuàng)建并發(fā)隊(duì)列,然后再執(zhí)行barrier函數(shù),前面ABC三個(gè)任務(wù)隨機(jī),后面DE隨機(jī),但是DE的執(zhí)行必須是等待ABC任務(wù)執(zhí)行完的。

第三種 NSOperation

NSBlockOperation *operatioon1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任務(wù)A");
    }];

    NSBlockOperation *operatioon2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任務(wù)B");
    }];

    NSBlockOperation *operatioon3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任務(wù)C");
    }];

    NSBlockOperation *operatioon4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任務(wù)D");
    }];

    [operatioon4 addDependency:operatioon1];
    [operatioon4 addDependency:operatioon2];
    [operatioon4 addDependency:operatioon3];

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperations:@[operatioon1,operatioon2,operatioon3,operatioon4] waitUntilFinished:YES];
    NSLog(@"完成之后的操作");

通過任務(wù)之間的依賴關(guān)系執(zhí)行,最后的參數(shù)YES的時(shí)候是會(huì)阻塞當(dāng)前線程,執(zhí)行完之后再往后執(zhí)行,NO的話就不阻塞

可以看到,上面的都是異步并發(fā)操作,而里面的任務(wù)是同步的,這里的任務(wù)指的是Block里面的所有操作,但是如果Block里面的操作是網(wǎng)絡(luò)請求,也是異步的,那上面的做法就會(huì)有問題了,看如下代碼

錯(cuò)誤例子

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_async(group, queue, ^{
        NSLog(@"同步任務(wù)A");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"網(wǎng)絡(luò)異步任務(wù)AA");
        });
    });

    dispatch_group_async(group, queue, ^{
        NSLog(@"同步任務(wù)B");
    });

    dispatch_group_async(group, queue, ^{
        NSLog(@"同步任務(wù)C");
    });

    dispatch_group_notify(group, queue, ^{
        NSLog(@"任務(wù)完成執(zhí)行");
    });
//    2018-04-18 10:53:16.294263+0800 GCD[3287:115681] 同步任務(wù)B
//    2018-04-18 10:53:16.294263+0800 GCD[3287:115679] 同步任務(wù)C
//    2018-04-18 10:53:16.294263+0800 GCD[3287:115699] 同步任務(wù)A
//    2018-04-18 10:53:16.294430+0800 GCD[3287:115699] 任務(wù)完成執(zhí)行
//    2018-04-18 10:53:18.294592+0800 GCD[3287:115646] 網(wǎng)絡(luò)異步任務(wù)AA

用dispatch_after來模擬網(wǎng)絡(luò)請求,可以看到,同步任務(wù)ABC->D這些操作還是正確的,但是里面有個(gè)模擬網(wǎng)絡(luò)請求的任務(wù),就不會(huì)按我們所想的順序執(zhí)行了。為什么呢?很簡單,首先都是異步的,子線程操作,而且是并發(fā)隊(duì)列,那么任務(wù)可以多個(gè)一起,如果任務(wù)是單純的打印,即同步任務(wù),那么就能完成我們的預(yù)期,如果Block任務(wù)里面還嵌套異步任務(wù),因?yàn)椴l(fā)隊(duì)列里面的任務(wù),只是負(fù)責(zé)打印和發(fā)送請求的操作,異步回調(diào)數(shù)據(jù)是不歸隊(duì)列管的,任務(wù)的執(zhí)行完畢,只是Block代碼塊代碼執(zhí)行完,如果里面還包含異步任務(wù),這里就需要通過信號(hào)量dispatch_semaphore來實(shí)現(xiàn)了。

下面就來實(shí)現(xiàn)如果并發(fā)隊(duì)列里面的任務(wù)是網(wǎng)絡(luò)請求,如何等ABC三個(gè)網(wǎng)絡(luò)請求回調(diào)之后,再執(zhí)行D?

先來介紹下Dispatch_semaphore的使用

dispatch_semaphore是GCD用來同步的一種方式,與他相關(guān)的共有三個(gè)函數(shù),分別是dispatch_semaphore_create,dispatch_semaphore_signal,dispatch_semaphore_wait,信號(hào)量1的時(shí)候一般都當(dāng)做鎖來看待。

參考文章:關(guān)于dispatch_semaphore的使用

異步并發(fā)(模擬網(wǎng)絡(luò)異步任務(wù))

子線程同時(shí)執(zhí)行ABC三個(gè)同步任務(wù)、全部執(zhí)行完成再在子線程執(zhí)行三個(gè)同步任務(wù)D。

說隊(duì)列組/依賴基本可以確定了解GCD/NSOpertion。但是比較麻煩、用線程?hào)艡赿ispatch_barrier的話會(huì)更簡便一些

這個(gè)就是上面的同步介紹面試題

上一題中的ABC三個(gè)任務(wù)改成異步任務(wù)(如AFN網(wǎng)絡(luò)請求)、全部回調(diào)成功后進(jìn)行數(shù)據(jù)整合。
如果只說隊(duì)列/任務(wù)組肯定不行。因?yàn)榫W(wǎng)絡(luò)請求本身是異步的、任務(wù)會(huì)立即完成、但數(shù)據(jù)還沒有回來。
最好的就是在隊(duì)列組的前提下。把異步的網(wǎng)絡(luò)請求轉(zhuǎn)化為同步、以捕獲正確的完成時(shí)機(jī)。
具體操作需要使用信號(hào)量。

這里有個(gè)帖子有介紹這個(gè),但是沒有具體Demo,下面看看如何組合信號(hào)量實(shí)現(xiàn)的

第一種 dispatch_group + semaphore

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_group_async(group, queue, ^{
        NSLog(@"同步任務(wù)A");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"網(wǎng)絡(luò)異步任務(wù)一");
            dispatch_semaphore_signal(semaphore);
        });
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    });

    dispatch_group_async(group, queue, ^{

        NSLog(@"同步任務(wù)B");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.8f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"網(wǎng)絡(luò)異步任務(wù)二");
            dispatch_semaphore_signal(semaphore);
        });
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    });

    dispatch_group_async(group, queue, ^{
        NSLog(@"同步任務(wù)C");
    });

    dispatch_group_async(group, queue, ^{

        NSLog(@"同步任務(wù)D");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"網(wǎng)絡(luò)異步任務(wù)四");
            dispatch_semaphore_signal(semaphore);
        });
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    });

    dispatch_group_notify(group, queue, ^{
        NSLog(@"任務(wù)完成執(zhí)行");
    });

image

分析如下:

異步并發(fā)隊(duì)列,里面添加了四個(gè)任務(wù),任務(wù)AB有網(wǎng)絡(luò)請求,C同步任務(wù)打印,D也有網(wǎng)絡(luò)請求,如何在ABCD四個(gè)任務(wù)完成,而且網(wǎng)絡(luò)請求也完成之后執(zhí)行之后的操作?

可以看到,Block整個(gè)就是一個(gè)任務(wù),如果沒有dispatch_semaphore_wait,帶有網(wǎng)絡(luò)請求的任務(wù),因?yàn)榫W(wǎng)絡(luò)請求本身是異步的、任務(wù)會(huì)立即完成、但數(shù)據(jù)還沒有回來。,因?yàn)榘l(fā)送網(wǎng)絡(luò)請求,就已經(jīng)把Block的任務(wù)完成了,異步回來的操作已經(jīng)不屬于并發(fā)隊(duì)列里面的管理的任務(wù)了。就和上面的錯(cuò)誤例子一樣,完成任務(wù)的執(zhí)行,和請求回調(diào)沒有任何順序關(guān)系了。那么如果我們在Block里面加了dispatch_semaphore_wait,什么意思呢?如果信號(hào)量為0的時(shí)候,那么就會(huì)一直在這里等待。可以理解為一開始發(fā)送網(wǎng)絡(luò)請求出去,這個(gè)時(shí)候執(zhí)行到wait函數(shù),信號(hào)量為0,等待,隊(duì)列任務(wù)沒有執(zhí)行完,只有當(dāng)請求回來的時(shí)候調(diào)用singnal的時(shí)候,信號(hào)+1,wait的函數(shù)隨機(jī)獲取到信號(hào),放開任務(wù),執(zhí)行完畢一個(gè),剩下的沒有獲取到的信號(hào)繼續(xù)等待,那么就會(huì)按我們的,執(zhí)行完一個(gè)網(wǎng)絡(luò)請求,信號(hào)+1,釋放一個(gè)wait,執(zhí)行完一個(gè)Block任務(wù),那么,當(dāng)所有的網(wǎng)絡(luò)請求執(zhí)行完,所有的wait都被釋放,任務(wù)都完成了,才會(huì)通知Group調(diào)用完成。

第二種 dispatch_group_enter 和 dispatch_group_leave

dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"同步任務(wù)A");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"網(wǎng)絡(luò)異步任務(wù)一");
            dispatch_group_leave(group);
        });
    });

    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{

        NSLog(@"同步任務(wù)B");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.8f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"網(wǎng)絡(luò)異步任務(wù)二");
            dispatch_group_leave(group);
        });
    });
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"同步任務(wù)C");
        dispatch_group_leave(group);
    });

    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{

        NSLog(@"同步任務(wù)D");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"網(wǎng)絡(luò)異步任務(wù)四");
            dispatch_group_leave(group);
        });
    });

    dispatch_group_notify(group, queue, ^{
        NSLog(@"任務(wù)完成執(zhí)行");
    });

這種方法也是我之前項(xiàng)目中用的,也能實(shí)現(xiàn)上面的執(zhí)行順序。

ABCD異步順序隨機(jī),無論任務(wù)是否有異步,都會(huì)等任務(wù)執(zhí)行完(包括網(wǎng)絡(luò)請求)再執(zhí)行任務(wù)完成

異步串行(同步任務(wù))

這個(gè)沒什么好說的,同步任務(wù),在串行隊(duì)列,肯定順序執(zhí)行

異步串行(異步任務(wù))

但是如果串行隊(duì)列里面的任務(wù)是網(wǎng)絡(luò)請求如何,再讓等網(wǎng)絡(luò)請求回調(diào)之后也順序執(zhí)行?

看代碼 不做處理

dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"執(zhí)行任務(wù)一");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"網(wǎng)絡(luò)任務(wù)一");
        });
    });

    dispatch_async(queue, ^{
        NSLog(@"執(zhí)行任務(wù)二");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"網(wǎng)絡(luò)任務(wù)二");
        });
    });

    dispatch_async(queue, ^{
        NSLog(@"執(zhí)行任務(wù)三");
    });

    dispatch_async(queue, ^{
        NSLog(@"執(zhí)行完成");
    });
    2018-04-18 12:11:04.956900+0800 GCD[4889:182340] 執(zhí)行任務(wù)一
    2018-04-18 12:11:04.957076+0800 GCD[4889:182340] 執(zhí)行任務(wù)二
    2018-04-18 12:11:04.957183+0800 GCD[4889:182340] 執(zhí)行任務(wù)三
    2018-04-18 12:11:04.957290+0800 GCD[4889:182340] 執(zhí)行完成
    2018-04-18 12:11:05.557397+0800 GCD[4889:182291] 網(wǎng)絡(luò)任務(wù)二
    2018-04-18 12:11:07.156658+0800 GCD[4889:182291] 網(wǎng)絡(luò)任務(wù)一

可以看到串行隊(duì)列任務(wù)執(zhí)行是順序的,但是異步網(wǎng)絡(luò)請求回調(diào)是不按順序的。下面我們用dispatch_semaphore處理下

dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"執(zhí)行任務(wù)一");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"網(wǎng)絡(luò)任務(wù)一");
            dispatch_semaphore_signal(semaphore);
        });
    });

    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"執(zhí)行任務(wù)二");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"網(wǎng)絡(luò)任務(wù)二");
            dispatch_semaphore_signal(semaphore);
        });
    });

    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"執(zhí)行任務(wù)三");
        dispatch_semaphore_signal(semaphore);
    });

    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"執(zhí)行完成");
        dispatch_semaphore_signal(semaphore);
    });

    2018-04-18 13:54:20.412918+0800 GCD[6841:262952] 執(zhí)行任務(wù)一
    2018-04-18 13:54:22.413131+0800 GCD[6841:262916] 網(wǎng)絡(luò)任務(wù)一
    2018-04-18 13:54:22.413369+0800 GCD[6841:262952] 執(zhí)行任務(wù)二
    2018-04-18 13:54:23.073214+0800 GCD[6841:262916] 網(wǎng)絡(luò)任務(wù)二
    2018-04-18 13:54:23.073512+0800 GCD[6841:262952] 執(zhí)行任務(wù)三
    2018-04-18 13:54:23.073697+0800 GCD[6841:262952] 執(zhí)行完成

當(dāng)異步串行隊(duì)列,而且任務(wù)有網(wǎng)絡(luò)異步請求,我們需要用信號(hào)量,每次開放一個(gè)任務(wù),當(dāng)一個(gè)任務(wù)無論是同步還是異步,都是操作完之后再把信號(hào)量+1,然后下一個(gè)任務(wù)才會(huì)解鎖。這里的信號(hào)量可以當(dāng)做鎖來理解。

總結(jié)

異步并發(fā)執(zhí)行同步任務(wù),可以用dispatch_group,dispatch_barrier和NSOperation的依賴

異步串行執(zhí)行同步任務(wù),默認(rèn)就是順序執(zhí)行

異步并發(fā)執(zhí)行異步任務(wù),可以用dispatch_group+semaphore 初始化信號(hào)為0,執(zhí)行完一個(gè)異步通過singnal釋放一個(gè)wait任務(wù)

或者用disaptch_group_enter 和 dispatch_group_leave

異步串行執(zhí)行異步任務(wù),可以用dispatch_semaphore 初始化信號(hào)為1,順序執(zhí)行任務(wù),每個(gè)任務(wù)都加鎖,執(zhí)行任務(wù)消耗鎖,順延任務(wù)等待,執(zhí)行完一個(gè)任務(wù),singnal,然后下一個(gè)任務(wù)開鎖順序執(zhí)行

如果多個(gè)任務(wù)網(wǎng)絡(luò)請求,NSOperation我感覺無法實(shí)現(xiàn) 多網(wǎng)絡(luò)任務(wù)執(zhí)行完之后再最終統(tǒng)一執(zhí)行某一個(gè)人任務(wù)。這個(gè)時(shí)候只有用dispatch_group + semaphore來實(shí)現(xiàn)

延伸閱讀:

作者:半島夏天
鏈接:http://www.lxweimin.com/p/6145cbe8cc3c
來源:簡書
簡書著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,055評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,346評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,889評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,118評(píng)論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,637評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,558評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,739評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,980評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評(píng)論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,347評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,702評(píng)論 2 370

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