iOS開發(fā)之多線程GCD

目前多線程主要分為三類:

1 NSThread
2 NSOperation
3 GCD
前面兩種網(wǎng)上資料很多,本文就蘋果推薦使用的GCD理一理。

多線程相關(guān)概念

進(jìn)程與線程的關(guān)系?

進(jìn)程:app打開的時候會打開相應(yīng)的進(jìn)程,一般情況下,一個App會有一個或多個進(jìn)程,但是iOS的App一般只有一個進(jìn)程(后臺播放,IM除外)。在iOS系統(tǒng)中,打開一個新的App會掛起其他App的進(jìn)程。一個進(jìn)程會包含一個或多個線程。
線程:一個線程同時只可以執(zhí)行一個任務(wù),多線程就可以同時執(zhí)行多個任務(wù)。一個進(jìn)程可以包含多個線程。

主線程和子線程(非主線程)到底有什么區(qū)別?

  • 主線程:iOS程序中,主線程(又叫作UI線程)主要任務(wù)是處理UI事件,顯示和刷新UI,(只有主線程有直接修改UI的能力)耗時的操作放在子線程(又叫作后臺線程、異步線程)。
  • 子線程:在iOS中開子線程去處理耗時的操作,可以有效提高程序的執(zhí)行效率,提高資源利用率。

但是開啟線程會占用一定的內(nèi)存,(主線程的堆棧大小是1M,第二個線程開始都是512KB,并且該值不能通過編譯器開關(guān)或線程API函數(shù)來更改)降低程序的性能。所以一般不要同時開很多線程。

注:查看當(dāng)前線程信息用[NSThread currentThread],而不要用[NSOperationQueue currentQueue],因前者內(nèi)容可以看到更全面的線程信息!

下面進(jìn)入正題:

GCD

關(guān)鍵字:

(1). 異步與同步

異步執(zhí)行:具備開新線程的能力,可以先繞過線程任務(wù),回頭再執(zhí)行。
同步執(zhí)行:不具備開新線程的能力,因此只能在當(dāng)前線程中執(zhí)行!任務(wù)執(zhí)行必須按順序執(zhí)行(必須執(zhí)行完當(dāng)前任務(wù)才會繼續(xù)走代碼)。

(2). 并發(fā)隊列與串行隊列

并發(fā)隊列:隊列中的任務(wù)同時執(zhí)行(Concurrent Dispatch Queue)
串行隊列:隊列中的任務(wù)按添加任務(wù)順序執(zhí)行(Serial Dispatch Queue)

注:這里說的任務(wù)就是GCD中block中的代碼。

這里的關(guān)鍵字一般都是組合用,理解單個是沒有意義的,組合后的效果:

注:如果同步執(zhí)行的時候,不放入新創(chuàng)建的線程中的話,就會在主線程執(zhí)行。

以下兩種同步執(zhí)行的情況都是在主線程執(zhí)行的:

    dispatch_queue_t concurrentQueue = dispatch_queue_create("abcd", DISPATCH_QUEUE_CONCURRENT);//并發(fā)隊列
    //這里的abcd僅僅作為調(diào)試時用的標(biāo)識符,打印線程屬性時并不是name
    dispatch_sync(concurrentQueue, ^{
        [self loadImage:@10];
    });
    dispatch_sync(concurrentQueue, ^{
        [self loadImage:@11];
    });
    dispatch_sync(concurrentQueue, ^{
        [self loadImage:@12];
    });
    dispatch_sync(concurrentQueue, ^{
        [self loadImage:@13];
    });

打印log:

2017-06-28 10:38:54.797 多線程GCD[80605:13173361] 執(zhí)行:10 線程信息:<NSThread: 0x600000073ec0>{number = 1, name = main}
2017-06-28 10:38:57.342 多線程GCD[80605:13173361] 執(zhí)行:11 線程信息:<NSThread: 0x600000073ec0>{number = 1, name = main}
2017-06-28 10:38:59.681 多線程GCD[80605:13173361] 執(zhí)行:12 線程信息:<NSThread: 0x600000073ec0>{number = 1, name = main}
2017-06-28 10:39:01.966 多線程GCD[80605:13173361] 執(zhí)行:13 線程信息:<NSThread: 0x600000073ec0>{number = 1, name = main}
    dispatch_queue_t serialQueue = dispatch_queue_create("aa", DISPATCH_QUEUE_SERIAL);//串行隊列
    //這里的DISPATCH_QUEUE_SERIAL等價于NULL
    dispatch_sync(serialQueue, ^{
        [self loadImage:@5];
    });
    dispatch_sync(serialQueue, ^{
        [self loadImage:@6];
    });
    dispatch_sync(serialQueue, ^{
        [self loadImage:@7];
    });
    dispatch_sync(serialQueue, ^{
        [self loadImage:@8];
    });

打印log:

2017-06-28 10:45:30.928 多線程GCD[81007:13250389] 執(zhí)行:5 線程信息:<NSThread: 0x600000065000>{number = 1, name = main}
2017-06-28 10:45:37.232 多線程GCD[81007:13250389] 執(zhí)行:6 線程信息:<NSThread: 0x600000065000>{number = 1, name = main}
2017-06-28 10:45:39.713 多線程GCD[81007:13250389] 執(zhí)行:7 線程信息:<NSThread: 0x600000065000>{number = 1, name = main}
2017-06-28 10:45:42.314 多線程GCD[81007:13250389] 執(zhí)行:8 線程信息:<NSThread: 0x600000065000>{number = 1, name = main}

正確的打開方式:

    dispatch_queue_t serialQueue = dispatch_queue_create("aa", DISPATCH_QUEUE_SERIAL);//串行隊列
    
    dispatch_async(dispatch_queue_create("abcd", DISPATCH_QUEUE_SERIAL), ^{
        
        dispatch_sync(serialQueue, ^{
            [self loadImage:@5];
        });
        dispatch_sync(serialQueue, ^{
            [self loadImage:@6];
        });
        dispatch_sync(serialQueue, ^{
            [self loadImage:@7];
        });
        dispatch_sync(serialQueue, ^{
            [self loadImage:@8];
        });
        
    });

打印log:

2017-06-28 10:47:15.677 多線程GCD[81128:13270066] 執(zhí)行:5 線程信息:<NSThread: 0x60800007e000>{number = 3, name = (null)}
2017-06-28 10:47:18.103 多線程GCD[81128:13270066] 執(zhí)行:6 線程信息:<NSThread: 0x60800007e000>{number = 3, name = (null)}
2017-06-28 10:47:20.470 多線程GCD[81128:13270066] 執(zhí)行:7 線程信息:<NSThread: 0x60800007e000>{number = 3, name = (null)}
2017-06-28 10:47:22.774 多線程GCD[81128:13270066] 執(zhí)行:8 線程信息:<NSThread: 0x60800007e000>{number = 3, name = (null)}

以上說的是同步的時候需要注意的,下面說一下異步的情況:

dispatch_queue_t serialQueue = dispatch_queue_create("aa", DISPATCH_QUEUE_SERIAL);//串行隊列
    
    dispatch_async(serialQueue, ^{
        [self loadImage:@0];
    });
    dispatch_async(serialQueue, ^{
        [self loadImage:@1];
    });
    dispatch_async(serialQueue, ^{
        [self loadImage:@2];
    });
    dispatch_async(serialQueue, ^{
        [self loadImage:@3];
    });

打印log:

2017-06-28 10:49:14.498 多線程GCD[81251:13288476] 執(zhí)行:0 線程信息:<NSThread: 0x600000262680>{number = 3, name = (null)}
2017-06-28 10:49:17.125 多線程GCD[81251:13288476] 執(zhí)行:1 線程信息:<NSThread: 0x600000262680>{number = 3, name = (null)}
2017-06-28 10:49:19.599 多線程GCD[81251:13288476] 執(zhí)行:2 線程信息:<NSThread: 0x600000262680>{number = 3, name = (null)}
2017-06-28 10:49:21.934 多線程GCD[81251:13288476] 執(zhí)行:3 線程信息:<NSThread: 0x600000262680>{number = 3, name = (null)}
dispatch_queue_t concurrentQueue = dispatch_queue_create("abcd", DISPATCH_QUEUE_CONCURRENT);//并發(fā)隊列
    
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@0];
    });
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@1];
    });
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@2];
    });
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@3];
    });

打印log:

2017-06-28 10:54:06.805 多線程GCD[81549:13342819] 執(zhí)行:1 線程信息:<NSThread: 0x608000072f80>{number = 4, name = (null)}
2017-06-28 10:54:06.805 多線程GCD[81549:13341379] 執(zhí)行:0 線程信息:<NSThread: 0x60800007b200>{number = 3, name = (null)}
2017-06-28 10:54:06.805 多線程GCD[81549:13342821] 執(zhí)行:3 線程信息:<NSThread: 0x6080000743c0>{number = 6, name = (null)}
2017-06-28 10:54:06.805 多線程GCD[81549:13342820] 執(zhí)行:2 線程信息:<NSThread: 0x60000026a400>{number = 5, name = (null)}

在串行隊列異步執(zhí)行過程中,會創(chuàng)建一個線程,按順序執(zhí)行當(dāng)前線程中的任務(wù)。有阻塞!
在并發(fā)隊列異步執(zhí)行過程中,可能會創(chuàng)建多個線程,同時執(zhí)行當(dāng)前線程中的任務(wù)。沒有阻塞!

        dispatch_async(dispatch_queue_create("aaa", DISPATCH_QUEUE_SERIAL), ^{
            [self loadImage:@0];
        });
        dispatch_async(dispatch_queue_create("bbb", DISPATCH_QUEUE_SERIAL), ^{
            [self loadImage:@1];
        });
        dispatch_async(dispatch_queue_create("ccc", DISPATCH_QUEUE_SERIAL), ^{
            [self loadImage:@2];
        });
        dispatch_async(dispatch_queue_create("ddd", DISPATCH_QUEUE_SERIAL), ^{
            [self loadImage:@3];
        });
        dispatch_async(dispatch_queue_create("eee", DISPATCH_QUEUE_SERIAL), ^{
            [self loadImage:@4];
        });

打印log:

2017-06-28 11:05:10.966 多線程GCD[82282:13469275] 執(zhí)行:2 線程信息:<NSThread: 0x608000076100>{number = 5, name = (null)}
2017-06-28 11:05:10.966 多線程GCD[82282:13469905] 執(zhí)行:4 線程信息:<NSThread: 0x6080000738c0>{number = 6, name = (null)}
2017-06-28 11:05:10.966 多線程GCD[82282:13469278] 執(zhí)行:3 線程信息:<NSThread: 0x608000075b40>{number = 7, name = (null)}
2017-06-28 11:05:10.966 多線程GCD[82282:13469331] 執(zhí)行:1 線程信息:<NSThread: 0x600000076d00>{number = 4, name = (null)}
2017-06-28 11:05:10.966 多線程GCD[82282:13469276] 執(zhí)行:0 線程信息:<NSThread: 0x60800006dcc0>{number = 3, name = (null)}

以上會創(chuàng)建5個串行隊列線程,而不是1個串行隊列線程,因為不是同一個線程,所以執(zhí)行順序是同時執(zhí)行,互相沒有影響(對于并發(fā)隊列是同樣的)。
正確使用方法應(yīng)該是1中創(chuàng)建的方式,對于并發(fā)隊列,計算機(jī)會根據(jù)性能和需要創(chuàng)建合理的線程數(shù)量。保證系統(tǒng)高性能和流暢性。

        dispatch_async(dispatch_queue_create("a", DISPATCH_QUEUE_CONCURRENT), ^{
            [self loadImage:@14];
        });
        dispatch_async(dispatch_queue_create("b", DISPATCH_QUEUE_CONCURRENT), ^{
            [self loadImage:@15];
        });
        dispatch_async(dispatch_queue_create("c", DISPATCH_QUEUE_CONCURRENT), ^{
            [self loadImage:@16];
        });
        dispatch_async(dispatch_queue_create("d", DISPATCH_QUEUE_CONCURRENT), ^{
            [self loadImage:@17];
        });

打印log:

2017-06-28 11:03:51.193 多線程GCD[82177:13453338] 執(zhí)行:15 線程信息:<NSThread: 0x608000263040>{number = 4, name = (null)}
2017-06-28 11:03:51.193 多線程GCD[82177:13449499] 執(zhí)行:14 線程信息:<NSThread: 0x608000261580>{number = 3, name = (null)}
2017-06-28 11:03:51.193 多線程GCD[82177:13453339] 執(zhí)行:16 線程信息:<NSThread: 0x608000272f00>{number = 5, name = (null)}
2017-06-28 11:03:51.193 多線程GCD[82177:13453340] 執(zhí)行:17 線程信息:<NSThread: 0x60000026e740>{number = 6, name = (null)}


Main Dispatch Queue/Global Dispatch Queue

實(shí)際上不用特意生成Dispatch Queue,系統(tǒng)也會為我們準(zhǔn)備幾個。那就是Main Dispatch Queue和Global Dispatch Queue。

Main Dispatch Queue就是主線程,因為主線程只有一個,所以Main Dispatch Queue是Serial Dispatch Queue。Main Dispatch Queue的處理在主線程的Runloop中執(zhí)行。

相應(yīng)的,Global Dispatch Queue是系統(tǒng)為我們準(zhǔn)備的Concurrent Dispatch Queue。Global Dispatch Queue有四個優(yōu)先級,應(yīng)根據(jù)需求使用對應(yīng)優(yōu)先級。

優(yōu)先級.png
  /**
   high優(yōu)先級的獲取方法
  */
 dispatch_queue_t globalHighQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
  /**
   default優(yōu)先級的獲取方法
  */
 dispatch_queue_t globalDefaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  /**
   low優(yōu)先級的獲取方法
  */
 dispatch_queue_t globalLowQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
  /**
   background優(yōu)先級的獲取方法
  */
 dispatch_queue_t globalBackgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

更改隊列優(yōu)先級:dispatch_set_target_queue(dispatch_object_t _Nonnull object, dispatch_queue_t _Nullable queue)

 dispatch_queue_t serialQueue = dispatch_queue_create("aa", DISPATCH_QUEUE_SERIAL);//串行隊列
    
 dispatch_queue_t globalBackgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    
 dispatch_set_target_queue(serialQueue, globalBackgroundQueue);將serialQueue指定為globalBackgroundQueue用。

注:如果這里用函數(shù)dispatch_set_target_queue將多個Serial Dispatch Queue指定為同一個Serial Dispatch Queue,就會將原本并發(fā)的隊列變更為串行隊列。

關(guān)鍵字 Dispatch Group
/**
將原本在serialQueue中要執(zhí)行的放在group里,后面可以加一個結(jié)束的回調(diào)(很多時候會有這種需求)
*/
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, serialQueue, ^{
        //代碼
    });
    dispatch_group_async(group, serialQueue, ^{
        //代碼
    });
    dispatch_group_async(group, serialQueue, ^{
        //代碼
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"done");//執(zhí)行完成后回調(diào)
    });
關(guān)鍵字 dispatch_barrier_async 柵欄
 dispatch_queue_t concurrentQueue = dispatch_queue_create("abcd", DISPATCH_QUEUE_CONCURRENT);//并行隊列
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@0];
        //讀取數(shù)據(jù)0
    });
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@1];
        //讀取數(shù)據(jù)1
    });
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@2];
        //讀取數(shù)據(jù)2
    });
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@3];
        //讀取數(shù)據(jù)3
    });
    dispatch_barrier_async(concurrentQueue, ^{
        [self loadImage:@4];
       //異步柵欄寫入數(shù)據(jù)4
    });
    dispatch_barrier_sync(concurrentQueue, ^{
        [self loadImage:@4];
        //同步柵欄寫入數(shù)據(jù)4
    });
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@5];
        //讀取數(shù)據(jù)5
    });
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@6];
        //讀取數(shù)據(jù)6
    });
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@7];
        //讀取數(shù)據(jù)7
    });
    dispatch_async(concurrentQueue, ^{
        [self loadImage:@8];
        //讀取數(shù)據(jù)8
    });

打印log:

2017-06-28 11:11:53.029 多線程GCD[82699:13543714] 執(zhí)行:2 線程信息:<NSThread: 0x600000076d80>{number = 5, name = (null)}
2017-06-28 11:11:53.029 多線程GCD[82699:13543650] 執(zhí)行:0 線程信息:<NSThread: 0x600000076d40>{number = 3, name = (null)}
2017-06-28 11:11:53.029 多線程GCD[82699:13543652] 執(zhí)行:1 線程信息:<NSThread: 0x608000066940>{number = 4, name = (null)}
2017-06-28 11:11:53.029 多線程GCD[82699:13543715] 執(zhí)行:3 線程信息:<NSThread: 0x608000071140>{number = 6, name = (null)}
2017-06-28 11:11:58.763 多線程GCD[82699:13544668] 異步柵欄執(zhí)行:4 線程信息:<NSThread: 0x6080000710c0>{number = 8, name = (null)}
2017-06-28 11:12:01.195 多線程GCD[82699:13542941] 同步柵欄執(zhí)行:4 線程信息:<NSThread: 0x600000066500>{number = 1, name = main}
2017-06-28 11:12:03.605 多線程GCD[82699:13543650] 執(zhí)行:7 線程信息:<NSThread: 0x600000076d40>{number = 3, name = (null)}
2017-06-28 11:12:03.605 多線程GCD[82699:13544677] 執(zhí)行:5 線程信息:<NSThread: 0x608000074bc0>{number = 9, name = (null)}
2017-06-28 11:12:03.605 多線程GCD[82699:13544668] 執(zhí)行:6 線程信息:<NSThread: 0x6080000710c0>{number = 8, name = (null)}
2017-06-28 11:12:03.605 多線程GCD[82699:13543714] 執(zhí)行:8 線程信息:<NSThread: 0x600000076d80>{number = 5, name = (null)}

在讀取數(shù)據(jù)時,有時候會出現(xiàn)數(shù)據(jù)競爭,數(shù)據(jù)安全問題,比如:當(dāng)前的寫入沒有結(jié)束,讀取操作就開始處理,導(dǎo)致數(shù)據(jù)錯亂。或者讀取正在進(jìn)行,開始寫入操作,導(dǎo)致程序崩潰等問題。
蘋果為我們提供了一個便捷的參數(shù):dispatch_barrier_async(柵欄)。

作用:如上述代碼中所表示,只有在1234操作完成時(無序),才會執(zhí)行寫入操作,只有當(dāng)前寫入操作結(jié)束后,才會繼續(xù)向下執(zhí)行。dispatch_barrier_sync也有同樣的效果,但是如果不放入其他線程中的話,會在當(dāng)前線程即主線程執(zhí)行,會阻塞線程。

注意:dispatch_barrier_async中如果使用全局隊列的話,就相當(dāng)于要等待全局隊列里的所有并發(fā)任務(wù)執(zhí)行完后,才會執(zhí)行dispatch_barrier_async中的任務(wù),這樣會受其他在全局隊列里任務(wù)的影響,達(dá)不到我們想要的效果。

總結(jié):
**
并發(fā)隊列(Concurrent Dispatch Queue) 串行隊列(Serial Dispatch Queue) :
負(fù)責(zé)執(zhí)行順序!
異步執(zhí)行 (dispatch_async) 同步執(zhí)行 (dispatch_sync):
負(fù)責(zé)選擇線程執(zhí)行!
**

上一篇:iOS開發(fā)系列:讓你的應(yīng)用“動”起來--Core Animation

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

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