Go語(yǔ)言并發(fā)、鎖向叉、channel

  • 多線程同時(shí)執(zhí)行叫做并行
  • 并發(fā)就是在不同線程中來(lái)回切換執(zhí)行來(lái)達(dá)到并行的效果就是并發(fā)
  • 通過(guò)go可以在當(dāng)前線程中開(kāi)啟一個(gè)協(xié)程
  • 保證協(xié)程被執(zhí)行,那么主線程不能掛掉

runtime包中常用的方法

  • runtime.Gosched()
  • 作用:用于出讓本次的執(zhí)行權(quán)限
  • 注意點(diǎn):讓出本次執(zhí)行權(quán)限并不意味著不再執(zhí)行
  • 應(yīng)用場(chǎng)景: 讓某些協(xié)程執(zhí)行的次數(shù)少一次, 讓某些協(xié)程執(zhí)行的次數(shù)多一些

  • runtime.Goexit()
  • 作用:終止調(diào)用它的go程,其他go程不受影響
  • 注意點(diǎn):這個(gè)go程將不會(huì)再被調(diào)用

  • runtime.NumCPU()

  • 獲取本地機(jī)器的邏輯CPU個(gè)數(shù)

  • runtime.GOMAXPROCS(num)

  • 設(shè)置可同時(shí)執(zhí)行的最大CPU數(shù),并返回上一次設(shè)置的CPU個(gè)數(shù)

  • 注意點(diǎn):Go1.8之后, 系統(tǒng)會(huì)自動(dòng)設(shè)置為最大值,了解------>忘記


互斥鎖

  • 當(dāng)使用互斥鎖后,當(dāng)前go程將不被再次調(diào)用
  • 案例一:有序打印
    /*
    需求: 定義個(gè)打印的函數(shù), 可以逐個(gè)的打印傳入字符串的每個(gè)字符
    在兩個(gè)協(xié)程中調(diào)用這個(gè)好方法, 并且還要保持輸出的內(nèi)容有序的
     */
  var lock = sync.Mutex{}
  func printer(str string){
  lock.Lock()//添加鎖,如果不添加那么可能執(zhí)行輸出hello也可能執(zhí)行輸出world,那么就是無(wú)序的
    for _,val := range str{
        fmt.Printf("%c", ch)
        time.Sleep(time.Millisecond * 300)
    }
  lock.Unlock()
  }
func main(){
  go printer("hello")
  go printer("world")
for{
    ;
  }
}

互斥鎖的資源搶奪問(wèn)題

  • 注意點(diǎn):如果兩個(gè)go程上了同一把鎖,那么當(dāng)一個(gè)go程被鎖上時(shí),另一個(gè)go程也會(huì)被鎖住
  • 案例二:生產(chǎn)者和消費(fèi)者
  var lock = sync.Mutex{}
  var buff = [10]int
  func producer(){
    lock.Lock()
    rand.Seed(time.Now().UnixNano())
    for i:=0; i < 10 ;i++{
        num := rand.Intn(100)
        fmt.Println("生產(chǎn)者生產(chǎn)了",num)
        buff[i] = num
        time.Sleep(time.Millisecond * 300)
    }
    lock.Unlock()
  }

 func consumer(){
    lock.Lock()
    for i:=0; i < 10 ;i++{
        buff[i] = num
        fmt.Println("消費(fèi)者消費(fèi)到了",num)
    }
    lock.Unlock()
  }

func main() {

    go producer()
    // 我們想要的是, 只有生產(chǎn)者生產(chǎn)了, 我們才能消費(fèi)
    // 注意點(diǎn): 在多go程中, 如果生產(chǎn)者生產(chǎn)的太慢, 那么消費(fèi)者就會(huì)消費(fèi)到錯(cuò)誤的數(shù)據(jù)
    go consumer()
    // 注意點(diǎn): 看上去通過(guò)給生產(chǎn)者以及消費(fèi)者同時(shí)加鎖就能解決, 只有生產(chǎn)完了才能消費(fèi)
    //         但是取決于誰(shuí)想執(zhí)行加鎖操作, 所以不完美
    for{
        ;
    }
}

  • 在上述案例中,只能一個(gè)生產(chǎn)者對(duì)應(yīng)一個(gè)消費(fèi)者,當(dāng)有第二個(gè)生產(chǎn)者或者第二個(gè)消費(fèi)者時(shí)會(huì)因?yàn)椴l(fā)而產(chǎn)生數(shù)據(jù)混亂锥腻。

  • 在上述案例中,無(wú)法判斷先執(zhí)行消費(fèi)者還是先執(zhí)行生產(chǎn)者,如果先進(jìn)入了調(diào)用者的go程,則會(huì)取不到數(shù)據(jù),就會(huì)發(fā)生數(shù)據(jù)混亂

  • 為了解決上述問(wèn)題,我們可以用管道來(lái)解決這個(gè)問(wèn)題

管道

  • 管道是一種數(shù)據(jù)類型,和字典切片很像,不用make函數(shù)創(chuàng)建就使用會(huì)報(bào)錯(cuò)
  • 格式: var 變量名稱 chan 數(shù)據(jù)類型 ---------> var myCh chan int
  • 作用:在Go語(yǔ)言的協(xié)程中, 一般都使用管道來(lái)保證多個(gè)協(xié)程的同步, 或者多個(gè)協(xié)程之間的通訊
var myCh chan int
myCh = make(chan int, 3)
  • 以上代碼創(chuàng)建了一個(gè)容量為3的管道(注意:長(zhǎng)度默認(rèn)為0,添加數(shù)據(jù)以后長(zhǎng)度會(huì)動(dòng)態(tài)變化)

管道的使用

管道寫(xiě)入數(shù)據(jù)

  • myChan<-
var myCh chan int
myCh = make(chan int, 3)
myCh<-666  //寫(xiě)入了一個(gè)數(shù)據(jù)666

管道讀取數(shù)據(jù)

  • <-myChan
var myCh chan int
myCh = make(chan int, 3)
myCh<-666  //寫(xiě)入了一個(gè)數(shù)據(jù)666
fmt.Println(<-myCh) //讀取了666

管道寫(xiě)入和讀取的注意點(diǎn)

  • 沒(méi)有創(chuàng)建管道容量直接使用會(huì)報(bào)錯(cuò)
var myCh chan int
myCh<-666  //報(bào)錯(cuò)
  • 管道中沒(méi)有數(shù)據(jù)時(shí)讀取會(huì)報(bào)錯(cuò)
var myCh chan int
myCh = make(chan int, 3)
fmt.Println(<-myCh) //報(bào)錯(cuò)
  • 管道已滿,再向管道中寫(xiě)入數(shù)據(jù)會(huì)報(bào)錯(cuò)
var myCh chan int
myCh = make(chan int, 3)
myCh<-1 //寫(xiě)入了一個(gè)數(shù)據(jù)1
myCh<-2 //寫(xiě)入了一個(gè)數(shù)據(jù)2
myCh<-3 //寫(xiě)入了一個(gè)數(shù)據(jù)3
myCh<-4 //報(bào)錯(cuò)

管道的關(guān)閉

  • close(管道名稱)
  • 注意點(diǎn):管道關(guān)閉以后不能再管道中寫(xiě)入數(shù)據(jù),但是可以在管道中讀取數(shù)據(jù)

管道的遍歷

  • 可以使用for循環(huán), 也可以使用 for range循環(huán), 以及死循環(huán)來(lái)遍歷。
  • 更推薦使用后兩者母谎。因?yàn)樵谄髽I(yè)開(kāi)發(fā)中, 有可能我們不知道管道中具體有多少條數(shù)據(jù), 所以如果利用for循環(huán)來(lái)遍歷, 那么無(wú)法確定遍歷的次數(shù), 并且如果遍歷的次數(shù)太多, 還會(huì)報(bào)錯(cuò)

for range遍歷

  • 注意點(diǎn):在寫(xiě)完數(shù)據(jù)以后必須關(guān)閉管道,否則會(huì)報(bào)錯(cuò)
  • 一般企業(yè)開(kāi)發(fā)中,管道數(shù)據(jù)寫(xiě)完之后都會(huì)將管道關(guān)閉
var myCh chan int
myCh = make(chan int, 3)
myCh<-1 //寫(xiě)入了一個(gè)數(shù)據(jù)1
myCh<-2 //寫(xiě)入了一個(gè)數(shù)據(jù)2
myCh<-3 //寫(xiě)入了一個(gè)數(shù)據(jù)3
close()//管道必須關(guān)閉,否則報(bào)錯(cuò)
for v := range myChan{
  fmt.Println(v) //先后輸出 1 2 3
}

死循環(huán)遍歷

  • 注意點(diǎn): 如果被遍歷的管道沒(méi)有關(guān)閉, 那么會(huì)報(bào)錯(cuò)
  • 如果管道被關(guān)閉, 那么會(huì)將true返回給ok, 否則會(huì)將false返回給Ok
var myCh chan int
myCh = make(chan int, 3)
myCh<-1 //寫(xiě)入了一個(gè)數(shù)據(jù)1
myCh<-2 //寫(xiě)入了一個(gè)數(shù)據(jù)2
myCh<-3 //寫(xiě)入了一個(gè)數(shù)據(jù)3
close()//管道必須關(guān)閉,否則報(bào)錯(cuò)
for{
  if value,ok:= <-myChan;ok{
       fmt.Println(v) //先后輸出 1 2 3
  }
}

管道的阻塞現(xiàn)象(重點(diǎn))

  • 單獨(dú)在主線程中操作管道, 寫(xiě)滿了會(huì)報(bào)錯(cuò), 沒(méi)有數(shù)據(jù)去讀取也會(huì)報(bào)錯(cuò)

  • 只要在go程中操作管道, 無(wú)論有沒(méi)有寫(xiě)滿, 無(wú)論有沒(méi)有數(shù)據(jù)都會(huì)發(fā)生管道阻塞的現(xiàn)象

  • 阻塞現(xiàn)象(和輸入緩沖區(qū)很相似)

    • 在go程中,如果寫(xiě)滿了,再寫(xiě)入數(shù)據(jù),則不會(huì)報(bào)錯(cuò),等待管道中的數(shù)據(jù)被取出后再添加

    • 在go程中,沒(méi)有數(shù)據(jù)還在被取出,則不會(huì)報(bào)錯(cuò),等待管道中的數(shù)據(jù)被寫(xiě)入后再取出

利用管道阻塞實(shí)現(xiàn)并發(fā)串行

  var myChan chan int
  myChan = make(chan int,10)
  func producer(){
    rand.Seed(time.Now().UnixNano())
    for i:=0; i < 10 ;i++{
        num := rand.Intn(100)
        myChan <- num
        fmt.Println("生產(chǎn)者生產(chǎn)了",num)
        time.Sleep(time.Millisecond * 300)
    }
  }
func producer2(){
    rand.Seed(time.Now().UnixNano())
    for i:=0; i < 10 ;i++{
        num := rand.Intn(100)
        myChan <- num
        fmt.Println("生產(chǎn)者生產(chǎn)了",num)
        time.Sleep(time.Millisecond * 300)
    }
  }

 func consumer(){
    for i:=0; i < 10 ;i++{
        num := <-myChan
        fmt.Println("消費(fèi)者消費(fèi)到了",num)
    }
  }

func main() {
    go producer()
    go producer2()
    go consumer()
    for{
        ;
    }
}
  • 以上代碼可以不止一個(gè)生產(chǎn)者或者消費(fèi)者

利用管道阻塞解決最后寫(xiě)死循環(huán)保證主線程不掛

  • 注意點(diǎn): 如果這個(gè)管道在協(xié)程中有被使用,那么編譯器會(huì)認(rèn)為主線程在取數(shù)據(jù)的時(shí)候會(huì)等待協(xié)程中輸入,并不會(huì)報(bào)錯(cuò)
  • go程執(zhí)行完后才向管道中填充數(shù)據(jù)
    var myCh = make(chan int, 3)
    var exitCh = make(chan bool, 1)
    go func() {
        for i:=0; i<3; i++ {
            fmt.Println("生產(chǎn)了數(shù)據(jù)", i)
            myCh<-i
        }
        exitCh<-true
    }()
    fmt.Println("exitCh之前的代碼")
    <-exitCh // 阻塞
    fmt.Println("exitCh之后的代碼")

無(wú)緩沖管道

  • 無(wú)緩沖管道沒(méi)有容量,在主程中既不可以讀也不可以寫(xiě)
  • 無(wú)緩沖區(qū)管道只能存在在go程中,并且如果在同一個(gè)go程中,無(wú)論先讀或者先寫(xiě)都會(huì)阻塞
  • 讀寫(xiě)必須都存在,但如果都在主程中會(huì)報(bào)錯(cuò),在同一個(gè)go程中會(huì)阻塞
  • 無(wú)緩沖管道如果存在在不同的go程中,先讀或者先寫(xiě)無(wú)所謂
   //在go程中可以只讀或者只寫(xiě),會(huì)阻塞
    myCh := make(chan int, 0)
    go func() {
        fmt.Println("123")
        myCh<-998
        //<-myCh
        fmt.Println("abc")
    }()

無(wú)緩沖管道解決死循環(huán)

//定義一個(gè)沒(méi)有緩沖的管道
    exitCh := make(chan bool)

    go func() {
        for i:= 0; i < 5; i++ {
            myCh<-i
            fmt.Println("生產(chǎn)了", i)
        }
        exitCh<-true
    }()
    //for{
    //  ;
    //}
    //time.Sleep(time.Second)
    <-exitCh

單向管道和雙向管道

  • 默認(rèn)情況下所有的管道都是雙向的管道(可讀可寫(xiě))

  • 那么在企業(yè)開(kāi)發(fā)中, 我們可能會(huì)需要將管道作為函數(shù)的參數(shù), 并且還需要限制函數(shù)中如何使用管道,那么這個(gè)時(shí)候我們就可能會(huì)使用單向管道

  • 格式:
    雙向格式:
    var myCh chan int;
    myCh = make(chan int, 5)
    myCh = make(chan int)

    單向格式:
    var myCh chan<- int; 只寫(xiě)的管道
    var myCh <-chan int; 只讀的管道

  • 注意點(diǎn):
    1.雙向管道可以賦值給單向管道
    2.單向管道賦值給雙向管道會(huì)報(bào)錯(cuò)

單向管道作為函數(shù)參數(shù)
  • 增強(qiáng)了代碼的語(yǔ)義
  • 管道是地址傳遞
// 定義一個(gè)函數(shù)模擬生產(chǎn)者
func producer(buff chan<- int)  {
    rand.Seed(time.Now().UnixNano()) // 種隨機(jī)種子
    for i:=0; i<5;i++  {
        // 產(chǎn)生隨機(jī)數(shù)
        num := rand.Intn(100)
        fmt.Println("生產(chǎn)者生產(chǎn)了", num)
        // 將生產(chǎn)好的數(shù)據(jù)放入緩沖區(qū)
        buff<-num
        //time.Sleep(time.Millisecond * 300)
    }
}

// 定義一個(gè)函數(shù)模擬消費(fèi)者
func consumer(buff <-chan int, exitCh chan<- int)  {
    for i:=0; i<5;i++  {
        num := <-buff
        fmt.Println("-------消費(fèi)者消費(fèi)到了", num)
    }
    exitCh<-666
}

func main() {
    // 定義一個(gè)數(shù)組模擬緩沖區(qū)
    var buff = make(chan int, 5)
    var exitCh = make(chan int)
    go producer(buff)
    go consumer(buff, exitCh)

    <-exitCh
    fmt.Println("程序結(jié)束了")
    //for{
    //  ;
    //}
}

管道是指針類型

    var myCh1 chan int = make(chan int, 5)
    //fmt.Println(myCh1) // 0xc042094000
    //fmt.Printf("%p\n", myCh1) // 0xc042094000
    //fmt.Printf("%p\n", &myCh1) // 0xc042082018
    myCh1<-1
    myCh1<-2

    var myCh2 <-chan int
    myCh2 = myCh1 // 將雙向的管道轉(zhuǎn)換成單向的管道
    // 打印單向管道的長(zhǎng)度和容量
    fmt.Println("len", len(myCh2), "cap", cap(myCh2))//len 2 cap 5
    fmt.Println(<-myCh2)//1
    // 打印雙向管道的長(zhǎng)度和容量
    fmt.Println("len", len(myCh1), "cap", cap(myCh1))//len 1 cap 5

select結(jié)構(gòu)

  • select選擇結(jié)構(gòu)和switch很像,如果所有case不滿足則會(huì)執(zhí)行default
  • 企業(yè)開(kāi)發(fā)中一般不會(huì)使用default,因?yàn)槿菀捉?jīng)常跑進(jìn)default
  • 企業(yè)開(kāi)發(fā)中,一般通過(guò)select用于消費(fèi)多個(gè)管道中的數(shù)據(jù)
  • 企業(yè)開(kāi)發(fā)中,一般通過(guò)select控制是否超時(shí)
  • 企業(yè)開(kāi)發(fā)中,一般通過(guò)select控制退出主線程
  • 以下是一個(gè)生產(chǎn)消費(fèi)的案例
    // 1.創(chuàng)建一個(gè)管道
    myCh1 := make(chan int, 5)
    myCh2 := make(chan int, 5)
    exitCh := make(chan bool)

    // 2.開(kāi)啟一個(gè)協(xié)程生產(chǎn)數(shù)據(jù)
    go func() {
        //time.Sleep(time.Second * 5) 如果存在這行數(shù)據(jù)會(huì)打印超時(shí)了,不存在則會(huì)正常消費(fèi)
        for i := 0; i < 10 ; i++ {
            myCh1<-i
            fmt.Println("生產(chǎn)者1生產(chǎn)了", i)
        }
        close(myCh1)
        exitCh<-true
    }()

go func() {
        time.Sleep(time.Second * 5)
        for i := 0; i < 10 ; i++ {
            myCh2<-i
            fmt.Println("生產(chǎn)者2生產(chǎn)了", i)
        }
        close(myCh2)
    }()

for{
        select {
        case num1 := <-myCh1:
            fmt.Println("------消費(fèi)者消費(fèi)了myCh1", num1)
        case <-time.After(3):
            fmt.Println("超時(shí)了")
            return
        }
        time.Sleep(time.Millisecond)
    }
    fmt.Println("程序結(jié)束了")

定時(shí)器

  • 想使用定時(shí)器需要使用time包

一次性定時(shí)器

NewTimer函數(shù)

  • 有一個(gè)Time結(jié)構(gòu)體
    • type Timer struct {
      C <-chan Time
      r runtimeTimer
      }
  • 作用, 就是讓系統(tǒng)在指定時(shí)間之后, 往Timer結(jié)構(gòu)體的C屬性中寫(xiě)入當(dāng)前的時(shí)間
  • NewTimer的函數(shù)接收一個(gè)時(shí)間,代表阻塞多少秒后寫(xiě)入時(shí)間
  • 注意:該函數(shù)返回的是一個(gè)Time結(jié)構(gòu)體,要調(diào)用其屬性必須 名稱.屬性
     start := time.Now()
     fmt.Println(start) //打印當(dāng)前時(shí)間
     timer := time.NewTimer(time.Second * 3) // Timer
     fmt.Println(<-timer.C) //打印三秒后的時(shí)間

After函數(shù)

  • After的函數(shù)接收一個(gè)時(shí)間,代表阻塞多少秒后寫(xiě)入時(shí)間
  • 注意:該函數(shù)返回的是一個(gè)Time結(jié)構(gòu)體中C的屬性
    start := time.Now()
    fmt.Println(start)
    timer := time.After(time.Second * 3) // Timer.C
    fmt.Println(<-timer)

周期性定時(shí)器

  • time包中有一個(gè)NewTicker的函數(shù),接收一個(gè)時(shí)間,表明阻塞多少秒向Time結(jié)構(gòu)體中寫(xiě)入數(shù)據(jù)
  • 注意點(diǎn):該函數(shù)會(huì)反復(fù)往結(jié)構(gòu)體中寫(xiě)入數(shù)據(jù),所以需要關(guān)閉,可以用stop函數(shù)進(jìn)行關(guān)閉
    start := time.Now()
    fmt.Println(start)
    ticker := time.NewTicker(time.Second * 2)
    for{
        fmt.Println(<-ticker.C)
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瘦黑,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子奇唤,更是在濱河造成了極大的恐慌幸斥,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,185評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咬扇,死亡現(xiàn)場(chǎng)離奇詭異甲葬,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)懈贺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,445評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門经窖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人梭灿,你說(shuō)我怎么就攤上這事画侣。” “怎么了堡妒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,684評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵配乱,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我皮迟,道長(zhǎng)搬泥,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,564評(píng)論 1 284
  • 正文 為了忘掉前任万栅,我火速辦了婚禮,結(jié)果婚禮上西疤,老公的妹妹穿的比我還像新娘烦粒。我一直安慰自己,他們只是感情好代赁,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,681評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布扰她。 她就那樣靜靜地躺著,像睡著了一般芭碍。 火紅的嫁衣襯著肌膚如雪徒役。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,874評(píng)論 1 290
  • 那天窖壕,我揣著相機(jī)與錄音忧勿,去河邊找鬼杉女。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鸳吸,可吹牛的內(nèi)容都是我干的熏挎。 我是一名探鬼主播,決...
    沈念sama閱讀 39,025評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼晌砾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼坎拐!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起养匈,我...
    開(kāi)封第一講書(shū)人閱讀 37,761評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤哼勇,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后呕乎,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體积担,經(jīng)...
    沈念sama閱讀 44,217評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,545評(píng)論 2 327
  • 正文 我和宋清朗相戀三年楣嘁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了磅轻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,694評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逐虚,死狀恐怖聋溜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情叭爱,我是刑警寧澤撮躁,帶...
    沈念sama閱讀 34,351評(píng)論 4 332
  • 正文 年R本政府宣布,位于F島的核電站买雾,受9級(jí)特大地震影響把曼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜漓穿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,988評(píng)論 3 315
  • 文/蒙蒙 一嗤军、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧晃危,春花似錦叙赚、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,778評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至鳍鸵,卻和暖如春苇瓣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背偿乖。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,007評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工击罪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哲嘲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,427評(píng)論 2 360
  • 正文 我出身青樓外邓,卻偏偏與公主長(zhǎng)得像撤蚊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子损话,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,580評(píng)論 2 349

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