iOS 多線程技術(shù) GCD

1枯夜、介紹

  1. 什么是GCD堵漱?
    Grand Central Dispatch,是蘋(píng)果公司開(kāi)發(fā)的一套多核編程的底層API莱找。GCD首次發(fā)布在Mac OS X 10.6酬姆,iOS4及以上也可用。GCD存在于libdispatch.dylib這個(gè)庫(kù)中宋距,iOS程序默認(rèn)動(dòng)態(tài)加載這個(gè)庫(kù)轴踱,無(wú)需手動(dòng)引入。
  2. GCD工作原理
    讓程序平行排隊(duì)的特定任務(wù)谚赎,根據(jù)可用的處理資源淫僻,安排他們?cè)谌魏慰捎玫奶幚砥骱诵纳蠄?zhí)行任務(wù)诱篷。一個(gè)任務(wù)可以是一個(gè)Function或是一個(gè)block。GCD的底層依然是用線程實(shí)現(xiàn)雳灵,不過(guò)這樣可以讓程序員不用關(guān)注實(shí)現(xiàn)的細(xì)節(jié)棕所。
  3. GCD優(yōu)勢(shì)
    GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核(比如雙核、四核)悯辙。
    GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出琳省,放到對(duì)應(yīng)的線程中執(zhí)行,任務(wù)的取出遵循隊(duì)列的FIFO原則躲撰。
  4. GCD核心概念
    任務(wù)(block)和隊(duì)列(queue)针贬。

2、隊(duì)列(Dispatch Queue)

  1. GCD隊(duì)列可以分為兩大類型:串行隊(duì)列和并發(fā)隊(duì)列拢蛋。
    串行隊(duì)列(Serial Dispatch Queue):同時(shí)只執(zhí)行一個(gè)任務(wù)桦他,通常用于同步訪問(wèn)特定的資源或數(shù)據(jù)。當(dāng)你創(chuàng)建多個(gè)串行隊(duì)列時(shí)谆棱,雖然它們各自是同步執(zhí)行的快压,但隊(duì)列之間是并發(fā)執(zhí)行的。
    并發(fā)隊(duì)列(Concurrent Dispatch Queue):可以讓多個(gè)任務(wù)并發(fā)執(zhí)行(自動(dòng)開(kāi)啟多個(gè)線程同時(shí)執(zhí)行任務(wù)垃瞧,如果同時(shí)執(zhí)行10個(gè)任務(wù)蔫劣,那么10個(gè)任務(wù)并不是開(kāi)啟10個(gè)線程,線程會(huì)根據(jù)任務(wù)執(zhí)行情況復(fù)用个从,具體線程數(shù)由系統(tǒng)決定)脉幢,并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效,執(zhí)行完成的順序是隨機(jī)的信姓。
  2. GCD兩種獲取隊(duì)列的方式:手動(dòng)創(chuàng)建和獲取系統(tǒng)提供的鸵隧。

(1)dispatch_queue_create(手動(dòng)創(chuàng)建隊(duì)列)
【語(yǔ)法】
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

示例

- (void)dispatchQueueCreateTest
 {
     NSLog(@"A:%@", [NSThread currentThread]);
     dispatch_queue_t queue = dispatch_queue_create("com.jinnchang.gcd", DISPATCH_QUEUE_SERIAL);
     dispatch_async(queue, ^{
         NSLog(@"B:%@", [NSThread currentThread]);
     });
     dispatch_async(queue, ^{
         NSLog(@"C:%@", [NSThread currentThread]);
     });
     NSLog(@"D:%@", [NSThread currentThread]);
 }
 // 打印結(jié)果:
 // 2021-05-09 13:59:26.984 GCDDemo[3714:99120] A:{number = 1, name = main}
 // 2021-05-09 13:59:26.984 GCDDemo[3714:99120] D:{number = 1, name = main}
 // 2021-05-09 13:59:26.984 GCDDemo[3714:99215] B:{number = 2, name = (null)}
 // 2021-05-09 13:59:26.985 GCDDemo[3714:99215] C:{number = 2, name = (null)}

【說(shuō)明】
dispatch_queue_create參數(shù)中的label是隊(duì)列名稱,一般使用倒序的全域名(雖然可以不給隊(duì)列指定一個(gè)名稱意推,但是有名稱的隊(duì)列可以讓我們?cè)谟龅絾?wèn)題時(shí)更好調(diào)試)豆瘫。attr為DISPATCH_QUEUE_SERIAL時(shí)返回串行隊(duì)列,為DISPATCH_QUEUE_CONCURRENT時(shí)返回并發(fā)隊(duì)列(如果填NULL默認(rèn)是DISPATCH_QUEUE_SERIAL)菊值。

(2)dispatch_get_main_queue(獲取系統(tǒng)主隊(duì)列)外驱、dispatch_get_global_queue(獲取系統(tǒng)全局并發(fā)隊(duì)列)
【語(yǔ)法】
dispatch_queue_t dispatch_get_main_queue(void);
dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);

示例

- (void)mainAndGlobalQueueTest
 {
     NSLog(@"A:%@", [NSThread currentThread]);
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
         // 耗時(shí)操作
         NSLog(@"B:%@", [NSThread currentThread]);
         dispatch_async(dispatch_get_main_queue(), ^{
             // 更新界面操作
            NSLog(@"C:%@", [NSThread currentThread]);
         });
     });
     NSLog(@"D:%@", [NSThread currentThread]);
 }
 // 打印結(jié)果:
 // 2021-05-09 14:05:13.732 GCDDemo[3794:101596] A:{number = 1, name = main}
 // 2021-05-09 14:05:13.733 GCDDemo[3794:101596] D:{number = 1, name = main}
 // 2021-05-09 14:05:13.733 GCDDemo[3794:101653] B:{number = 2, name = (null)}
 // 2021-05-09 14:05:13.764 GCDDemo[3794:101596] C:{number = 1, name = main}

【說(shuō)明】
主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列,放在主隊(duì)列中的任務(wù),都會(huì)放到主線程中執(zhí)行腻窒。主線程是唯一可用于更新UI的線程昵宇。
GCD默認(rèn)已經(jīng)提供了全局的并發(fā)隊(duì)列,供整個(gè)應(yīng)用使用儿子,不需要手動(dòng)創(chuàng)建瓦哎。
dispatch_get_global_queue參數(shù)中的identifier是優(yōu)先級(jí),有如下四種;flags這個(gè)參數(shù)是留給以后用的蒋譬,暫時(shí)用不上割岛,傳0即可。

#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(rèn)(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺(tái)

3犯助、調(diào)度任務(wù)

1癣漆、dispatch_async(用異步的方式執(zhí)行任務(wù))
【語(yǔ)法】
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

示例

- (void)dispatchAsyncTest
 {
     NSLog(@"A:%@", [NSThread currentThread]);
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     dispatch_async(queue, ^{
         NSLog(@"B:%@", [NSThread currentThread]);
     });
     dispatch_async(queue, ^{
         NSLog(@"C:%@", [NSThread currentThread]);
     });
     NSLog(@"D:%@", [NSThread currentThread]);
 }
 // 打印結(jié)果:
 // 2021-05-09 14:18:43.040 GCDDemo[3965:106717] A:{number = 1, name = main}
 // 2021-05-09 14:18:43.041 GCDDemo[3965:106717] D:{number = 1, name = main}
 // 2021-05-09 14:18:43.041 GCDDemo[3965:106754] B:{number = 2, name = (null)}
 // 2021-05-09 14:18:43.041 GCDDemo[3965:106755] C:{number = 3, name = (null)}

【說(shuō)明】
異步方式具備開(kāi)啟新線程的能力。會(huì)立即返回剂买,不會(huì)堵塞當(dāng)前線程惠爽。

2、dispatch_sync(用同步方式執(zhí)行任務(wù))
【語(yǔ)法】
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

示例

- (void)dispatchSyncTest
 {
     NSLog(@"A:%@", [NSThread currentThread]);
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     dispatch_sync(queue, ^{
         NSLog(@"B:%@", [NSThread currentThread]);
     });
     dispatch_sync(queue, ^{
         NSLog(@"C:%@", [NSThread currentThread]);
     });
     NSLog(@"D:%@", [NSThread currentThread]);
 }
 // 打印結(jié)果:
 // 2021-05-09  14:22:38.085 GCDDemo[4032:108410] A:{number = 1, name = main}
 // 2021-05-09  14:22:38.085 GCDDemo[4032:108410] B:{number = 1, name = main}
 // 2021-05-09  14:22:38.086 GCDDemo[4032:108410] C:{number = 1, name = main}
 // 2021-05-09  14:22:38.086 GCDDemo[4032:108410] D:{number = 1, name = main}

【說(shuō)明】
同步方式不具備開(kāi)啟新線程的能力瞬哼。在堵塞在當(dāng)前線程中婚肆,等block執(zhí)行完成再返回。

3坐慰、dispatch_after(讓隊(duì)列任務(wù)延時(shí)執(zhí)行)
【語(yǔ)法】
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

示例

- (void)dispatchAfterTest
 {
     NSLog(@"A:%@", [NSThread currentThread]);
     dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
     dispatch_after(time, dispatch_get_main_queue(), ^{
         NSLog(@"B:%@", [NSThread currentThread]);
     });
     NSLog(@"C:%@", [NSThread currentThread]);
 }
 // 打印結(jié)果:
 // 2021-05-09 14:29:01.119 GCDDemo[4198:111631] A:{number = 1, name = main}
 // 2021-05-09 14:29:01.120 GCDDemo[4198:111631] C:{number = 1, name = main}
 // 2021-05-09 14:29:02.185 GCDDemo[4198:111631] B:{number = 1, name = main}

【說(shuō)明】
dispatch_after的真正含義是在設(shè)定的時(shí)間后把任務(wù)添加進(jìn)隊(duì)列中旬痹,并不是表示在設(shè)定的時(shí)間后執(zhí)行,大部分情況該函數(shù)能達(dá)到我們的預(yù)期讨越,只有在對(duì)時(shí)間要求非常精準(zhǔn)的情況下才可能會(huì)出現(xiàn)問(wèn)題,這種情況下就要慎重使用了永毅。
NSEC_PER_SEC表示的是秒數(shù)把跨,它還提供了NSEC_PER_MSEC表示毫秒數(shù)。

4沼死、dispatch_apply
【語(yǔ)法】
void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));

示例

- (void)dispatchApplyTest
 {
     NSLog(@"A:%@", [NSThread currentThread]);
     NSArray *array = @[@"B",@"C",@"D"];
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     dispatch_apply([array count], queue, ^(size_t index) {
         NSLog(@"%@:%@", [array objectAtIndex:index], [NSThread currentThread]);
     });
     NSLog(@"E:%@", [NSThread currentThread]);
 }
 // 打印結(jié)果:
 // 2021-05-09  14:33:34.729 GCDDemo[4306:113699] A:{number = 1, name = main}
 // 2021-05-09  14:33:34.729 GCDDemo[4306:113721] C:{number = 3, name = (null)}
 // 2021-05-09  14:33:34.729 GCDDemo[4306:113699] B:{number = 1, name = main}
 // 2021-05-09  14:33:34.729 GCDDemo[4306:113722] D:{number = 2, name = (null)}
 // 2021-05-09  14:33:34.730 GCDDemo[4306:113699] E:{number = 1, name = main}

【說(shuō)明】
如果要對(duì)某個(gè)數(shù)組中的所有元素執(zhí)行同樣的block的時(shí)候着逐,這個(gè)函數(shù)就顯得很有用了。并行運(yùn)算意蛀,然后等待所有運(yùn)算結(jié)束耸别。由于是并發(fā)隊(duì)列,不能保證哪個(gè)索引元素先執(zhí)行完县钥,但是dispatch_apply函數(shù)是同步的秀姐,執(zhí)行過(guò)程中會(huì)使線程在此處等待。如果需要整個(gè)操作異步執(zhí)行若贮,在dispatch_apply外再套一層dispatch_async可以實(shí)現(xiàn)省有。

5、dispatch_once
【語(yǔ)法】
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);

示例

+ (MyManager *)sharedInstance
 {
     static MyManager *sharedManager;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         sharedManager = [[MyManager alloc] init];
     });
     return sharedManager;
 }

【說(shuō)明】
dispatch_once通常用在單例模式上谴麦,保證在程序運(yùn)行期間block只執(zhí)行一次蠢沿。

6、dispatch_group_async
【語(yǔ)法】
void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

示例

- (void)dispatchGroupAsyncTest
 {
     NSLog(@"A:%@", [NSThread currentThread]);
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     dispatch_group_t group = dispatch_group_create();
     dispatch_group_async(group, queue, ^{
         NSLog(@"B:%@", [NSThread currentThread]);
     });
     dispatch_group_async(group, queue, ^{
         NSLog(@"C:%@", [NSThread currentThread]);
     });
     dispatch_group_notify(group, dispatch_get_main_queue(), ^{
         NSLog(@"D:%@", [NSThread currentThread]);
     });
     NSLog(@"E:%@", [NSThread currentThread]);
 }
 // 打印結(jié)果:
 // 2021-05-09 14:42:37.609 GCDDemo[4462:117434] A:{number = 1, name = main}
 // 2021-05-09 14:42:37.610 GCDDemo[4462:117434] E:{number = 1, name = main}
 // 2021-05-09 14:42:37.610 GCDDemo[4462:117480] B:{number = 3, name = (null)}
 // 2021-05-09 14:42:37.610 GCDDemo[4462:117481] C:{number = 2, name = (null)}
 // 2021-05-09 14:42:37.642 GCDDemo[4462:117434] D:{number = 1, name = main}

【說(shuō)明】
dispatch_group_async可以實(shí)現(xiàn)監(jiān)聽(tīng)一組任務(wù)是否完成匾效,完成后得到通知執(zhí)行其他的操作舷蟀。比如你執(zhí)行三個(gè)下載任務(wù),當(dāng)三個(gè)任務(wù)都下載完成后你才通知界面說(shuō)完成的了。除了使用dispatch_group_notify函數(shù)可以得到最后執(zhí)行完的通知外野宜,還可以使用dispatch_group_wait扫步。需要注意的是,dispatch_group_wait實(shí)際上會(huì)使當(dāng)前的線程處于等待的狀態(tài)速缨,也就是說(shuō)如果是在主線程執(zhí)行dispatch_group_wait锌妻,在Block執(zhí)行完之前,主線程會(huì)處于卡死的狀態(tài)旬牲。dispatch_group_wait的第二個(gè)參數(shù)是指定超時(shí)時(shí)間仿粹,如果指定為DISPATCH_TIME_FOREVER則表示會(huì)永久等待,直到Block全部執(zhí)行完原茅。

7吭历、dispatch_barrier_async
【語(yǔ)法】
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

示例

- (void)dispatchBarrierAsyncTest
 {
     NSLog(@"A:%@", [NSThread currentThread]);
     dispatch_queue_t queue = dispatch_queue_create("com.jinnchang.gcd", DISPATCH_QUEUE_CONCURRENT);
     dispatch_async(queue, ^{
         NSLog(@"B:%@", [NSThread currentThread]);
     });
     dispatch_async(queue, ^{
         NSLog(@"C:%@", [NSThread currentThread]);
     });
     dispatch_barrier_async(queue, ^{
         NSLog(@"D:%@", [NSThread currentThread]);
     });
     dispatch_async(queue, ^{
         NSLog(@"E:%@", [NSThread currentThread]);
     });
     dispatch_async(queue, ^{
         NSLog(@"F:%@", [NSThread currentThread]);
     });
     NSLog(@"G:%@", [NSThread currentThread]);
 }
 // 打印結(jié)果:
 // 2021-05-09 14:46:30.992 GCDDemo[4554:119327] A:{number = 1, name = main}
 // 2021-05-09 14:46:30.993 GCDDemo[4554:119327] G:{number = 1, name = main}
 // 2021-05-09 14:46:30.993 GCDDemo[4554:119367] C:{number = 2, name = (null)}
 // 2021-05-09 14:46:30.993 GCDDemo[4554:119366] B:{number = 3, name = (null)}
 // 2021-05-09 14:46:30.993 GCDDemo[4554:119366] D:{number = 3, name = (null)}
 // 2021-05-09 14:46:30.993 GCDDemo[4554:119367] F:{number = 2, name = (null)}
 // 2021-05-09 14:46:30.993 GCDDemo[4554:119366] E:{number = 3, name = (null)}

【說(shuō)明】
dispatch_barrier_async是在前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行,而且它后面的任務(wù)等它執(zhí)行完成之后才會(huì)執(zhí)行.
如果上述示例中dispatch_queue_t是使用dispatch_get_global_queue創(chuàng)建的會(huì)發(fā)現(xiàn)執(zhí)行順序與預(yù)想的不一致擂橘,原因是dispatch_barrier_async的順序執(zhí)行仍然依賴queue的類型晌区,必須要求是dispatch_queue_create創(chuàng)建的,而且attr參數(shù)值必須是DISPATCH_QUEUE_CONCURRENT通贞。

4朗若、管理調(diào)度對(duì)象

  1. dispatch_suspend、dispatch_resume
    【語(yǔ)法】
    void dispatch_suspend(dispatch_object_t object);
    void dispatch_resume(dispatch_object_t object);
    【說(shuō)明】
    dispatch_suspend(暫停)和dispatch_resume(恢復(fù))在主線程上不起作用昌罩。
    dispatch_suspend并不會(huì)立即暫停正在運(yùn)行的block哭懈,而是在當(dāng)前block執(zhí)行完成后,暫停后續(xù)的block執(zhí)行茎用。

  2. dispatch_release遣总、dispatch_retain
    在MRC中需要釋放手動(dòng)創(chuàng)建的隊(duì)列,在ARC中系統(tǒng)自動(dòng)釋放轨功。通過(guò)dispatch_get_main_queue和dispatch_get_global_queue獲取的系統(tǒng)全局隊(duì)列旭斥,不用retain或release。

5古涧、信號(hào)量

【語(yǔ)法】
dispatch_semaphore_t dispatch_semaphore_create(long value);
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
long dispatch_semaphore_signal(dispatch_semaphore_t dsema);

示例

- (void)dispatchSemaphoreTest
 {
     NSLog(@"A:%@", [NSThread currentThread]);
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
     NSArray *array = @[@"B", @"C", @"D", @"E"];
     for (int i = 0; i < [array count]; i++) {
         dispatch_async(queue, ^{
             dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
             [NSThread sleepForTimeInterval:1];
             NSLog(@"%@:%@", [array objectAtIndex:i], [NSThread currentThread]);
             dispatch_semaphore_signal(semaphore);
         });
     }
     NSLog(@"F:%@", [NSThread currentThread]);
 }
 // 打印結(jié)果:
 // 2021-05-09 14:50:54.840 GCDDemo[4675:121679] A:{number = 1, name = main}
 // 2021-05-09 14:50:54.840 GCDDemo[4675:121679] F:{number = 1, name = main}
 // 2021-05-09 14:50:55.842 GCDDemo[4675:121712] B:{number = 2, name = (null)}
 // 2021-05-09 14:50:56.843 GCDDemo[4675:121711] C:{number = 3, name = (null)}
 // 2021-05-09 14:50:57.845 GCDDemo[4675:121713] D:{number = 4, name = (null)}
 // 2021-05-09 14:50:58.846 GCDDemo[4675:121718] E:{number = 5, name = (null)}

【說(shuō)明】
信號(hào)量在多線程開(kāi)發(fā)中被廣泛使用垂券,當(dāng)一個(gè)線程在進(jìn)入一段關(guān)鍵代碼之前,線程必須獲取一個(gè)信號(hào)量羡滑,一旦該關(guān)鍵代碼段完成了圆米,那么該線程必須釋放信號(hào)量。其它想進(jìn)入該關(guān)鍵代碼段的線程必須等待前面的線程釋放信號(hào)量啄栓。
信號(hào)量的具體做法是:當(dāng)信號(hào)計(jì)數(shù)大于0時(shí)娄帖,每條進(jìn)來(lái)的線程使計(jì)數(shù)減1,直到變?yōu)?昙楚,變?yōu)?后其他的線程將進(jìn)不來(lái)近速,處于等待狀態(tài);執(zhí)行完任務(wù)的線程釋放信號(hào),使計(jì)數(shù)加1削葱,如此循環(huán)下去奖亚。另外dispatch_semaphore_wait同樣也支持超時(shí),只需要給其第二個(gè)參數(shù)指定超時(shí)的時(shí)候析砸,然后通過(guò)返回值來(lái)判斷昔字。

信號(hào)量實(shí)現(xiàn)原理詳細(xì)解釋

6、相關(guān)概念解析

1首繁、死鎖
【示例】

- (void)deadLockTest
 {
     NSLog(@"A:%@", [NSThread currentThread]);
     dispatch_sync(dispatch_get_main_queue(), ^{
         NSLog(@"B:%@", [NSThread currentThread]);
     });
     NSLog(@"C:%@", [NSThread currentThread]);
 }

【說(shuō)明】
上述代碼會(huì)發(fā)生死鎖作郭,因?yàn)橹骶€程通過(guò)dispatch_sync把block交給主隊(duì)列后,會(huì)等待block里的任務(wù)結(jié)束再往下走自身的任務(wù)弦疮,而隊(duì)列是先進(jìn)先出的夹攒,block里的任務(wù)也在等待主隊(duì)列當(dāng)中排在它之前的任務(wù)都執(zhí)行完了再走自己,這種循環(huán)等待就形成了死鎖胁塞。所以在主線程當(dāng)中使用dispatch_sync將任務(wù)加到主隊(duì)列是不可取的咏尝。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市啸罢,隨后出現(xiàn)的幾起案子编检,更是在濱河造成了極大的恐慌,老刑警劉巖扰才,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒙谓,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡训桶,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)酣倾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)舵揭,“玉大人,你說(shuō)我怎么就攤上這事躁锡∥缟” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵映之,是天一觀的道長(zhǎng)拦焚。 經(jīng)常有香客問(wèn)我,道長(zhǎng)杠输,這世上最難降的妖魔是什么赎败? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮蠢甲,結(jié)果婚禮上僵刮,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好搞糕,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布勇吊。 她就那樣靜靜地躺著,像睡著了一般窍仰。 火紅的嫁衣襯著肌膚如雪汉规。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,785評(píng)論 1 314
  • 那天驹吮,我揣著相機(jī)與錄音针史,去河邊找鬼。 笑死钥屈,一個(gè)胖子當(dāng)著我的面吹牛悟民,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播篷就,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼射亏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了竭业?” 一聲冷哼從身側(cè)響起智润,我...
    開(kāi)封第一講書(shū)人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎未辆,沒(méi)想到半個(gè)月后窟绷,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咐柜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年兼蜈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拙友。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡为狸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出遗契,到底是詐尸還是另有隱情辐棒,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布牍蜂,位于F島的核電站漾根,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鲫竞。R本人自食惡果不足惜辐怕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望从绘。 院中可真熱鬧秘蛇,春花似錦其做、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至艘策,卻和暖如春蹈胡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背朋蔫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工罚渐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人驯妄。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓荷并,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親青扔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子源织,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361

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