GO通道和 sync 包的分享

[TOC]

GO通道和 sync 包的分享

go通道和sync包.jpg

我們一起回顧一下上次分享的內(nèi)容:

  • GO協(xié)程同步若不做限制的話,會(huì)產(chǎn)生數(shù)據(jù)競(jìng)態(tài)的問(wèn)題
  • 我們用鎖的方式來(lái)解決如上問(wèn)題霹粥,根據(jù)使用場(chǎng)景選擇使用互斥鎖 和 讀寫鎖
  • 比使用鎖更好的方式是原子操作灭将,但是使用go的 sync/atomic需要小心使用疼鸟,因?yàn)樯婕皟?nèi)存

要是對(duì)GO的鎖和原子操作還感興趣的話后控,歡迎查看文章GO的鎖和原子操作分享

上次我們分享到鎖和原子操作,都可以保證共享數(shù)據(jù)的讀寫

可是空镜,他們還是會(huì)影響性能浩淘,不過(guò),Go 為開(kāi)發(fā)這提供了 通道 這個(gè)神器

今天我們來(lái)分享一下Go中推薦使用的其他同步方法吴攒,通道和 sync 包

image

通道是什么张抄?

是一種特殊的類型,是連接并發(fā)goroutine的管道

channel 通道是可以讓一個(gè) goroutine 協(xié)程發(fā)送特定值到另一個(gè) goroutine 協(xié)程的通信機(jī)制洼怔。

通道像一個(gè)傳送帶或者隊(duì)列署惯,總是遵循先入先出(First In First Out)的規(guī)則,保證收發(fā)數(shù)據(jù)的順序镣隶,這一點(diǎn)和管道是一樣的

一個(gè)協(xié)程從通道的一頭放入數(shù)據(jù)极谊,另一個(gè)協(xié)程從通道的另一頭讀出數(shù)據(jù)

每一個(gè)通道都是一個(gè)具體類型的導(dǎo)管,聲明 channel 的時(shí)候需要為其指定元素類型安岂。

通道能做什么轻猖?

控制協(xié)程的同步,讓程序有序運(yùn)行

GO 中提倡 不要通過(guò)共享內(nèi)存來(lái)通信域那,而通過(guò)通信來(lái)共享內(nèi)存

goroutine協(xié)程 是 Go 程序并發(fā)的執(zhí)行體咙边,channel 通道就是它們之間的連接,他們之間的橋梁次员,他們的交通樞紐

通道有哪幾種败许?

大致可分為如下三種:

image
  • 無(wú)緩沖通道
  • 有緩沖的通道
  • 單向通道

無(wú)緩沖通道

image

無(wú)緩沖的通道又稱為阻塞的通道

無(wú)緩沖通道上的發(fā)送操作會(huì)阻塞,直到另一個(gè)goroutine在該通道上執(zhí)行接收操作淑蔚,這時(shí)值才能發(fā)送成功

兩個(gè) goroutine 協(xié)程將繼續(xù)執(zhí)行

我們反過(guò)來(lái)看市殷,如果接收操作先執(zhí)行,接收方的goroutine將阻塞束倍,直到另一個(gè) goroutine 協(xié)程在該通道上發(fā)送一個(gè)數(shù)據(jù)

因此被丧,無(wú)緩沖通道也被稱為同步通道,因?yàn)槲覀兛梢允褂脽o(wú)緩沖通道進(jìn)行通信绪妹,利用發(fā)送和接收的 goroutine 協(xié)程同步化

有緩沖的通道

image

還是上述提到的甥桂,有緩沖通道,就是在初始化 / 創(chuàng)建通道 的 make 函數(shù)的第 2 個(gè)參數(shù)填上我們所期望的緩沖區(qū)大小 邮旷, 例如:

ch1 := make(chan int , 4)

此時(shí)黄选,該通道的容量為4,發(fā)送方可以一直向通道中發(fā)送數(shù)據(jù),直到通道滿办陷,且通道數(shù)據(jù)未被讀走時(shí)貌夕,發(fā)送方就會(huì)阻塞

只要通道的容量大于零,那么該通道就是有緩沖的通道

通道的容量表示通道中能存放元素的數(shù)量

我們可以使用內(nèi)置的 len函數(shù) 獲取通道內(nèi)元素的數(shù)量民镜,使用 cap函數(shù) 獲取通道的容量

單向通道

通道默認(rèn)是既可以讀有可以寫的啡专,但是單向通道就是要么只能讀,要么只能寫

  • chan <- int
image

是一個(gè)只能發(fā)送的通道制圈,可以發(fā)送但是不能接收

  • <- chan int
image

是一個(gè)只能接收的通道们童,可以接收但是不能發(fā)送

如何創(chuàng)建和聲明一個(gè)通道

聲明通道

在 Go 里面,channel是一種類型鲸鹦,默認(rèn)就是一種引用類型

簡(jiǎn)單解釋一下什么是引用:

在我們寫C++的時(shí)候慧库,用到引用會(huì)比較多

引用,顧名思義是某一個(gè)變量或?qū)ο蟮膭e名馋嗜,對(duì)引用的操作與對(duì)其所綁定的變量或?qū)ο蟮牟僮魍耆葍r(jià)

在C++里面是這樣用的:

類型 &引用名=目標(biāo)變量名齐板;

聲明一個(gè)通道

var 變量名 chan 元素類型

var ch1 chan string             // 聲明一個(gè)傳遞字符串?dāng)?shù)據(jù)的通道
var ch2 chan []int              // 聲明一個(gè)傳遞int切片數(shù)據(jù)的通道
var ch3 chan bool               // 聲明一個(gè)傳遞布爾型數(shù)據(jù)的通道
var ch4 chan interface{}        // 聲明一個(gè)傳遞接口類型數(shù)據(jù)的通道

看,聲明一個(gè)通道就是這么簡(jiǎn)單

對(duì)于通道來(lái)說(shuō)葛菇,關(guān)聲明了還不能使用甘磨,聲明的通道默認(rèn)是其對(duì)應(yīng)類型的零值,例如

  • int 類型 零值 就是 0
  • string 類型 零值就是個(gè) 空串
  • bool 類型 零值就是 false
  • 切片的 零值 就是 nil

我們還需要對(duì)通道進(jìn)行初始化才可以正常使用通道哦

初始化通道

一般是使用 make 函數(shù)初始化之后才能使用通道熟呛,也可以直接使用make函數(shù) 創(chuàng)建通道

例如:

ch5 := make(chan string)
ch6 := make(chan []int)
ch7 := make(chan bool)
ch8 := make(chan interface{})

make 函數(shù)的第二個(gè)參數(shù)是可以設(shè)置緩沖的大小的宽档,我們來(lái)看看源碼的說(shuō)明

// The make built-in function allocates and initializes an object of type
// slice, map, or chan (only). Like new, the first argument is a type, not a
// value. Unlike new, make's return type is the same as the type of its
// argument, not a pointer to it. The specification of the result depends on
// the type:
// Slice: The size specifies the length. The capacity of the slice is
// equal to its length. A second integer argument may be provided to
// specify a different capacity; it must be no smaller than the
// length. For example, make([]int, 0, 10) allocates an underlying array
// of size 10 and returns a slice of length 0 and capacity 10 that is
// backed by this underlying array.
// Map: An empty map is allocated with enough space to hold the
// specified number of elements. The size may be omitted, in which case
// a small starting size is allocated.
// Channel: The channel's buffer is initialized with the specified
// buffer capacity. If zero, or the size is omitted, the channel is
// unbuffered.
func make(t Type, size ...IntegerType) Type

如果 make 函數(shù)的第二個(gè)參數(shù)不填,那么就默認(rèn)是無(wú)緩沖的通道

現(xiàn)在我們來(lái)看看如何操作 channel 通道庵朝,都可以怎么玩

image

如何操作 channel

通道的操作有如下三種操作:

  • 發(fā)送(send)
  • 接收(receive)
  • 關(guān)閉(close)

對(duì)于發(fā)送和接收通道里面的數(shù)據(jù)吗冤,寫法就比較形象,使用 <- 來(lái)指向是從通道里面讀取數(shù)據(jù)九府,還是從通道中發(fā)送數(shù)據(jù)

向通道發(fā)送數(shù)據(jù)

// 創(chuàng)建一個(gè)通道
ch := make(chan int)
// 發(fā)送數(shù)據(jù)給通道
ch <- 1

我們看到箭頭的方向是椎瘟,1 指向了 ch 通道,所以不難理解侄旬,這是將1 這個(gè)數(shù)據(jù)肺蔚,放入通道中

從通道中接收數(shù)據(jù)

num := <-ch

不難看出,上述代碼是 ch 指向了一個(gè)需要初始化的變量儡羔,也就是說(shuō)宣羊,從 ch 中讀出一個(gè)數(shù)據(jù),賦值給 num

我們從通道中讀出數(shù)據(jù)汰蜘,也可以不進(jìn)行賦值仇冯,直接忽略也是可以的,如:

<-ch

關(guān)閉通道

Go中提供了 close 函數(shù)來(lái)關(guān)閉通道

close(ch)

對(duì)于關(guān)閉通道非常需要注意族操,用不好直接導(dǎo)致程序崩潰

image
  • 只有在通知接收方 goroutine 協(xié)程所有的數(shù)據(jù)都發(fā)送完畢的時(shí)候才需要關(guān)閉通道

  • 通道是可以被垃圾回收機(jī)制回收的苛坚,它和關(guān)閉文件是不一樣的膘掰,在結(jié)束操作之后關(guān)閉文件是必須要做的秧耗,但關(guān)閉通道不是必須的

關(guān)閉后的通道有以下 4 個(gè)特點(diǎn):

  • 對(duì)一個(gè)關(guān)閉的通道再發(fā)送值就會(huì)導(dǎo)致 panic
  • 對(duì)一個(gè)關(guān)閉的通道進(jìn)行接收會(huì)一直獲取值直到通道為空
  • 對(duì)一個(gè)關(guān)閉的并且沒(méi)有值的通道執(zhí)行接收操作會(huì)得到對(duì)應(yīng)類型的零值
  • 關(guān)閉一個(gè)已經(jīng)關(guān)閉的通道會(huì)導(dǎo)致 panic

通道異常情況梳理

我們來(lái)整理一下對(duì)于通道會(huì)存在的異常:

channel 狀態(tài) 未初始化的通道(nil) 通道非空 通道是空的 通道滿了 通道未滿
接收數(shù)據(jù) 阻塞 接收數(shù)據(jù) 阻塞 接收數(shù)據(jù) 接收數(shù)據(jù)
發(fā)送數(shù)據(jù) 阻塞 發(fā)送數(shù)據(jù) 發(fā)送數(shù)據(jù) 阻塞 發(fā)送數(shù)據(jù)
關(guān)閉 panic 關(guān)閉通道成功<br />待數(shù)據(jù)讀取完畢后<br />返回零值 關(guān)閉通道成功<br />直接返回零值 關(guān)閉通道成功<br />待數(shù)據(jù)讀取完畢后<br />返回零值 關(guān)閉通道成功<br />待數(shù)據(jù)讀取完畢后<br />返回零值

每一種通道的DEMO實(shí)戰(zhàn)

無(wú)緩沖通道

func main() {
   // 創(chuàng)建一個(gè)無(wú)緩沖的,數(shù)據(jù)類型 為 int 類型的通道
   ch := make(chan int)
   // 向通道中寫入 數(shù)字 1
   ch <- 1
   fmt.Println("send successfully ... ")
}

執(zhí)行上述代碼我們可以查看到效果

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
        F:/my_channel/main.go:9 +0x45
exit status 2

出現(xiàn)上述報(bào)錯(cuò) deadlock 錯(cuò)誤的原因愁茁,細(xì)心的小伙伴應(yīng)該能夠知道為什么银还,我上述有提到

image

我們使用 ch := make(chan int) 創(chuàng)建的是無(wú)緩沖的通道

無(wú)緩沖的通道只有在有接收方接收值的時(shí)候才能發(fā)送數(shù)據(jù)成功

我們可以想一下我們生活中的案例一樣:

你在某東上買了一個(gè)稍微貴重一點(diǎn)的物品熬词,某東快遞人員給你寄快遞的時(shí)候惫搏,打電話給你剥哑,必須要送到你的手上,不然不敢簽收涯贞,這個(gè)時(shí)候枪狂,你不方便,或者你不簽收宋渔,那么這個(gè)快遞就是算作沒(méi)有寄送成功

因此,上述問(wèn)題原因是辜限,創(chuàng)建了一個(gè)無(wú)緩沖通道皇拣,發(fā)送方一直在阻塞,通道中一直未有協(xié)程讀取數(shù)據(jù)薄嫡,導(dǎo)致死鎖

我們的解決辦法就是創(chuàng)建另外一個(gè)協(xié)程氧急,將數(shù)據(jù)從通道中讀出來(lái)即可

package main

import "fmt"

func recvData(c chan int) {
    ret := <-c
    fmt.Println("recvData successfully ... data = ", ret)
}

func main() {
    // 創(chuàng)建一個(gè)無(wú)緩沖的,數(shù)據(jù)類型 為 int 類型的通道
    ch := make(chan int)
    go recvData(ch)
    // 向通道中寫入 數(shù)字 1
    ch <- 1
    fmt.Println("send successfully ... ")
}

這里需要注意毫深,如果 go recvData(ch) 放在了 ch <- 1 之后吩坝,那么結(jié)果還是一樣的死鎖,原因還是因?yàn)? ch <- 1 會(huì)一直阻塞哑蔫,根本不會(huì)執(zhí)行到 他之后的語(yǔ)句

image

實(shí)際效果

recvData successfully ... data =  1
send successfully ...

有緩沖通道

func main() {
   // 創(chuàng)建一個(gè)無(wú)緩沖的钉寝,數(shù)據(jù)類型 為 int 類型的通道
   ch := make(chan int , 1)
   // 向通道中寫入 數(shù)字 1
   ch <- 1
   fmt.Println("send successfully ... ")
}

還是同樣的案例,同樣的代碼闸迷,我們只是把無(wú)緩沖通道嵌纲,換成了有緩沖的通道, 我們?nèi)匀徊粚iT開(kāi)協(xié)程讀取通道的數(shù)據(jù)

實(shí)際效果 腥沽, 發(fā)送成功
$$

$$

send successfully ...

因?yàn)榇藭r(shí)通道中的緩沖是1逮走,第一次向通道中發(fā)送數(shù)據(jù),不會(huì)阻塞今阳,

可是如果师溅,在通道中數(shù)據(jù)還未讀取出去之前,又向通道中寫入數(shù)據(jù)盾舌,則此處會(huì)阻塞墓臭,

若一直沒(méi)有協(xié)程從通道中讀取數(shù)據(jù),則結(jié)果與上述一樣矿筝,會(huì)死鎖

單向通道

package main

import "fmt"

func OnlyWriteData(out chan<- int) {
   // 單向 通道 起便, 只寫 不能讀
   for i := 0; i < 10; i++ {
      out <- i
   }
   close(out)
}

func CalData(out chan<- int, in <-chan int) {
   // out 單向 通道 , 只寫 不能讀
   // int 單向 通道 , 只讀 不能寫

   // 遍歷 讀取in 通道榆综,若 in通道 數(shù)據(jù)讀取完畢妙痹,則阻塞,若in 通道關(guān)閉鼻疮,則退出循環(huán)
   for i := range in {
      out <- i + i
   }
   close(out)
}
func myPrinter(in <-chan int) {
   // 遍歷 讀取in 通道怯伊,若 in通道 數(shù)據(jù)讀取完畢,則阻塞判沟,若in 通道關(guān)閉耿芹,則退出循環(huán)
   for i := range in {
      fmt.Println(i)
   }
}

func main() {
   // 創(chuàng)建2 個(gè)無(wú)緩沖的通道
   ch1 := make(chan int)
   ch2 := make(chan int)


   go OnlyWriteData(ch1)
   go CalData(ch2, ch1)


   myPrinter(ch2)
}

我們模擬 2 個(gè)通道,

  • 一個(gè) 只寫 不能讀
  • 一個(gè) 只讀 不能寫

實(shí)際效果

0
2
4
6
8
10
12
14
16
18

關(guān)閉通道

package main

import "fmt"

func main() {
   c := make(chan int)
   
   go func() {
      for i := 0; i < 10; i++ {
         // 循環(huán)向無(wú)緩沖的通道中寫入數(shù)據(jù)挪哄, 只有當(dāng)上一個(gè)數(shù)據(jù)被讀走之后吧秕,下一個(gè)數(shù)據(jù)才能往通道中放
         c <- i
      }
      // 關(guān)閉通道
      close(c)
   }()
   for {
      // 讀取通道中的數(shù)據(jù),若通道中無(wú)數(shù)據(jù)迹炼,則阻塞砸彬,若讀到 ok 為false, 則通道關(guān)閉斯入,退出循環(huán)
      if data, ok := <-c; ok {
         fmt.Println(data)
      } else {
         break
      }
   }
   fmt.Println("channel over")
}

再次強(qiáng)調(diào)一下關(guān)閉通道砂碉,demo 的模擬方式與上述的案例基本一致,感興趣的可以自己運(yùn)行看看效果

image

看到這里刻两,細(xì)心的小伙伴應(yīng)該可以總結(jié)出增蹭,判斷通道是否關(guān)閉的 2種 方式了吧?

  • 讀取通道的時(shí)候磅摹,判斷bool類型的變量是否為false

例如上述代碼

if data, ok := <-c; ok {
    fmt.Println(data)
} else {
    break
}

判斷 ok 為true滋迈,則正常讀取到數(shù)據(jù), 若為false 偏瓤,則通道關(guān)閉

  • 通過(guò) for range 的方式來(lái)遍歷通道杀怠,若退出循環(huán),則是因?yàn)橥ǖ狸P(guān)閉
image

sync 包

Go 的 sync 包也是用作實(shí)現(xiàn)并發(fā)任務(wù)的同步

還記得嗎厅克,在分享 文章GO的鎖和原子操作分享的時(shí)候赔退,我們就用到過(guò) sync 包

用法大同消息,這里列舉一下 sync 包涉及的數(shù)據(jù)結(jié)構(gòu)和方法

  • sync.WaitGroup
  • sync.Once
  • sync.Map

sync.WaitGroup

他是一個(gè)結(jié)構(gòu)體证舟,傳遞的時(shí)候要傳遞指針 硕旗,這里需要注意

他是并發(fā)安全的,內(nèi)部有維護(hù)一個(gè)計(jì)數(shù)器

涉及的方法:

  • (wg * WaitGroup) Add(delta int)

參數(shù)中 傳入的 delta 女责,表示 sync.WaitGroup 內(nèi)部的計(jì)數(shù)器 + delta

  • (wg *WaitGroup) Done()

表示當(dāng)前協(xié)程退出漆枚,計(jì)數(shù)器 -1

  • (wg *WaitGroup) Wait()

等待并發(fā)任務(wù)執(zhí)行完畢,此時(shí)的計(jì)數(shù)器為變成 0

sync.Once

他是并發(fā)安全的抵知,內(nèi)部有互斥鎖 和 一個(gè)布爾類型的數(shù)據(jù)

  • 互斥鎖 用于加鎖解鎖
  • 布爾類型的數(shù)據(jù) 用于記錄初始化是否完成

一般用于在高并發(fā)的場(chǎng)景下只執(zhí)行一次墙基,我們一下子就能想到的場(chǎng)景會(huì)有程序啟動(dòng)時(shí)软族,加載配置文件的場(chǎng)景

針對(duì)類似的場(chǎng)景,Go 也給我們提供了解決方法 残制,即 sync.Once 里面的 Do 方法

  • func (o *Once) Do(f func()) {}

Do 方法的參數(shù) 是一個(gè)函數(shù)立砸,可是我們要在該函數(shù)里面?zhèn)鬟f參數(shù)咋整?

image

可以使用Go 里面的閉包來(lái)實(shí)現(xiàn) 初茶, 閉包的具體實(shí)現(xiàn)方式颗祝,感興趣的可以深入了解一下

sync.Map

他是并發(fā)安全的,正是因?yàn)?Go 中的 map 是并發(fā)不安全的恼布,因此有了 sync.Map

sync.Map 有如下幾個(gè)明顯的優(yōu)勢(shì):

  • 并發(fā)安全
  • sync.Map 不需要使用 make 初始化螺戳,直接使用 myMap := sync.Map{} 即可使用 sync.Map 里面的方法

sync.Map 涉及的方法

見(jiàn)名知意

  • Store

存入 key 和value

  • Load

取出 某個(gè)key 對(duì)應(yīng)的 value

  • LoadOrStore

取出 并且 存入 2個(gè)操作

  • Delete

刪除key 和 對(duì)應(yīng)的 value

  • Range

遍歷所有key 和 對(duì)應(yīng)的 value

總結(jié)

  • 通道是什么,通道的種類
  • 無(wú)緩沖折汞,有緩沖倔幼,單向通道具體對(duì)應(yīng)什么
  • 對(duì)于通道的具體實(shí)踐
  • 分享了關(guān)于通道的異常情況整理
  • 簡(jiǎn)單分享了sync包的使用

歡迎點(diǎn)贊,關(guān)注字支,收藏

朋友們凤藏,你的支持和鼓勵(lì),是我堅(jiān)持分享堕伪,提高質(zhì)量的動(dòng)力

image

好了,本次就到這里栗菜,下一次 服務(wù)注冊(cè)與發(fā)現(xiàn)之 ETCD

技術(shù)是開(kāi)放的欠雌,我們的心態(tài),更應(yīng)是開(kāi)放的疙筹。擁抱變化富俄,向陽(yáng)而生,努力向前行而咆。

我是小魔童哪吒霍比,歡迎點(diǎn)贊關(guān)注收藏,下次見(jiàn)~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末暴备,一起剝皮案震驚了整個(gè)濱河市悠瞬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌涯捻,老刑警劉巖浅妆,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異障癌,居然都是意外死亡凌外,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門涛浙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)康辑,“玉大人摄欲,你說(shuō)我怎么就攤上這事〈保” “怎么了胸墙?”我有些...
    開(kāi)封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)惦辛。 經(jīng)常有香客問(wèn)我劳秋,道長(zhǎng),這世上最難降的妖魔是什么胖齐? 我笑而不...
    開(kāi)封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任玻淑,我火速辦了婚禮,結(jié)果婚禮上呀伙,老公的妹妹穿的比我還像新娘补履。我一直安慰自己,他們只是感情好剿另,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布箫锤。 她就那樣靜靜地躺著,像睡著了一般雨女。 火紅的嫁衣襯著肌膚如雪谚攒。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天氛堕,我揣著相機(jī)與錄音馏臭,去河邊找鬼。 笑死讼稚,一個(gè)胖子當(dāng)著我的面吹牛括儒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播锐想,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼帮寻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了赠摇?” 一聲冷哼從身側(cè)響起固逗,我...
    開(kāi)封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝉稳,沒(méi)想到半個(gè)月后抒蚜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耘戚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年嗡髓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片收津。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饿这,死狀恐怖浊伙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情长捧,我是刑警寧澤嚣鄙,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站串结,受9級(jí)特大地震影響哑子,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肌割,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一卧蜓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧把敞,春花似錦弥奸、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至耽装,卻和暖如春愤炸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掉奄。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工摇幻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挥萌。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像枉侧,于是被迫代替她去往敵國(guó)和親引瀑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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