【JS時間戳】獲取時間戳的最快方式探究

TAG

nodejs,nodejs時間戳,js時間戳,timestamp,date.now,performance.now,時間戳,小數(shù)取整,位運算,精度丟失,數(shù)字的存儲方式,小數(shù)的二進(jìn)制存儲,位運算的限制

獲取13位時間戳方法及性能簡單對比

以前獲取時間戳沒什么太認(rèn)真過鳞贷,今天突然突發(fā)奇想,哪種方式獲取時間戳最快呢?特別是常用的10位時間戳。然后了解到獲取時間戳的方式有很多種,比如網(wǎng)上常用的下面幾種方式(除了第一種):

// 下列速度依次遞減
performance.timeOrigin + performance.now()
Date.now()
new Date().getTime()
new Date().valueOf()
Date.parse(new Date())

// 下列兩個方法獲取時間差等
process.uptime()
process.hrtime()

通過如下代碼進(jìn)行驗證:

const performance = require('perf_hooks').performance;

let s, e, interval = 10000000
console.log(`獲取${interval}次時間戳速度對比:====================================`)

s = process.uptime()
for (let i = 0; i < interval; i++) performance.timeOrigin + performance.now()
e = process.uptime()
console.log('performance.timeOrigin+performance.now():', performance.timeOrigin + performance.now(), e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) Date.now()
e = process.uptime()
console.log('Date.now():', Date.now(), e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) new Date().getTime()
e = process.uptime()
console.log('new Date().getTime()', new Date().getTime(), e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) Date.parse(new Date())
e = process.uptime()
console.log('Date.parse(new Date())', Date.parse(new Date()), e - s)

結(jié)果如下:

獲取10000000次時間戳速度對比:====================================
performance.timeOrigin+performance.now(): 1596589863553.657 0.47400000000000003
Date.now(): 1596589864435 0.8799999999999999
new Date().getTime() 1596589866093 1.6569999999999998
Date.parse(new Date()) 1596589887000 21.115000000000002

除了第一種performance之外膘壶,其他幾種方式網(wǎng)上的比對一大堆,大家就自行了解啦。起初我也是以為Date.now()是最快的拐揭,但是當(dāng)帶著好奇去了解的時候,突然發(fā)現(xiàn)了這個performance奕塑,然后一測試發(fā)現(xiàn)了新大陸堂污!關(guān)于performance的介紹,請看我另外一篇轉(zhuǎn)載的文章:《解讀 Nodejs 性能 API:Performance Timing》

這幾種方式的對比這里就不再贅述了龄砰,由上往下速度遞減盟猖,performance完勝,更多詳細(xì)對比網(wǎng)上一大堆换棚。但是如果說獲取時間戳式镐,基本都是精確到毫秒的13位時間戳(除了Date.parse)。但是日常開發(fā)中很多時候用到的是10位時間戳固蚤,那么獲取10位時間戳的最快方式呢碟案?

獲取10位時間戳性能對比

驗證代碼如下:

const performance = require('perf_hooks').performance

let s, e, interval = 10000000

console.log(`\n\n獲取${interval}次10位時間戳速度對比:====================================`)
s = process.uptime()
for (let i = 0; i < interval; i++) Math.floor((performance.timeOrigin + performance.now()) / 1000)
e = process.uptime()
console.log('Math.floor((performance.timeOrigin + performance.now()) / 1000)', Math.floor((performance.timeOrigin + performance.now()) / 1000), e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) Math.floor(Date.now() / 1000)
e = process.uptime()
console.log('Math.floor(Date.now()/1000)', Math.floor(Date.now() / 1000), e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) Math.floor(new Date().getTime() / 1000)
e = process.uptime()
console.log('Math.floor(new Date().getTime()/1000)', Math.floor(new Date().getTime() / 1000), e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) Date.parse(new Date()) / 1000
e = process.uptime()
console.log('Date.parse(new Date())/1000', Date.parse(new Date()) / 1000, e - s)

結(jié)果如下:

獲取10000000次10位時間戳速度對比:====================================
Math.floor((performance.timeOrigin + performance.now()) / 1000) 1596591749 0.476
Math.floor(Date.now()/1000) 1596591750 0.889
Math.floor(new Date().getTime()/1000) 1596591751 1.6669999999999998
Date.parse(new Date())/1000 1596591774 22.153

所以還是performance完美勝出!

是否還有更快的方式颇蜡?

經(jīng)過上面測試价说,在我的目前的認(rèn)知范圍內(nèi)(小學(xué)生階段),也就是performance獲取13位時間戳的性能最高了风秤。那這種方式是否還有優(yōu)化的可能呢鳖目?

  1. 我們知道performance.timeOrigin是一個精確到微秒的變量,在系統(tǒng)運行的時候就直接將當(dāng)前的時間賦值給了它缤弦,所以獲取它應(yīng)該是沒有什么可以優(yōu)化的空間了领迈。
  2. 經(jīng)過測試,通過將數(shù)字轉(zhuǎn)換為字符或字符串后再取前幾位的方式,不論是空間復(fù)雜度還是時間復(fù)雜度來說和直接的數(shù)學(xué)運算來比相差很大狸捅,慢了好多倍衷蜓,所以,優(yōu)化的重點在觸發(fā)計算和取整這塊了尘喝。
  3. 那么優(yōu)化的空間可能就藏在除法計算和取整這個環(huán)節(jié)了磁浇。經(jīng)過一番對除法取整的探索,結(jié)果如下
    exact division
  • 通過Math庫取整及速度對比

可以看到朽褪,效率最高的還是Math.floor()這個方法置吓。這里就會聯(lián)想到Math.trunc(),它們兩個之間的性能在計算時間戳這塊的對比如何呢缔赠,代碼如下:

const performance = require('perf_hooks').performance;
let s, e, a, interval = 1000000000
console.log(`\n\n執(zhí)行${interval}次速度對比:====================================`)

a = (performance.timeOrigin + performance.now()) / 1000

s = process.uptime()
for (let i = 0; i < interval; i++) Math.floor(a)
e = process.uptime()
console.log('Math.floor', a, Math.floor(a), e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) Math.trunc(a)
e = process.uptime()
console.log('Math.trunc', a, Math.trunc(a), e - s)

對比結(jié)果如下衍锚,兩個性能差距相差不大,每次測試結(jié)果都大致相同:

執(zhí)行1000000000次速度對比:====================================
Math.floor 1596596494.6187212 1596596494 0.984
Math.trunc 1596596494.6187212 1596596494 0.984

執(zhí)行10000000000次速度對比:====================================
Math.floor 1596596596.3742654 1596596596 13.716
Math.trunc 1596596596.3742654 1596596596 14.643
  • 通過位運算進(jìn)行取整

更多位運算相關(guān)請移步《JS中的位運算》了解更多
通過位運算X|0,~~X,X^0,X>>0,X<<0都可以實現(xiàn)小數(shù)的取整

單豎杠“|”就是位運算中的按位或運算:
比如:3|4嗤堰,就是0011 | 0100=0111=4+2+1=7
再如:1596596596.3742654 | 0戴质,首先我們需要知道1596596596.3742654的二進(jìn)制存儲格式了。

JavaScript 只有一種數(shù)字類型 ( Number )
JavaScript采用 IEEE 754 標(biāo)準(zhǔn)雙精度浮點(double64)踢匣,64位中有1位符號位置森,11位存儲指數(shù),52位存儲浮點數(shù)的有效數(shù)字
有時候小數(shù)在二進(jìn)制中表示是無限的符糊,所以從53位開始就會舍入(舍入規(guī)則是0舍1入),這樣就造成了“浮點精度問題”(由于舍入規(guī)則有時大點呛凶,有時小點)

IEEE標(biāo)準(zhǔn)中float的存儲規(guī)則

IEEE標(biāo)準(zhǔn)中double的存儲規(guī)則

更多詳細(xì)介紹男娄,請參看傳送門

JS中小數(shù)的存儲方式

通過上面的了解,我們將上面的1596596596.3742654.toString(2)轉(zhuǎn)為二進(jìn)制字符串表示如下:
1011111001010100010000101110100.0101111111001111110111
但實際在內(nèi)存中的存儲如下:

  1. 首先將整數(shù)部分1596596596轉(zhuǎn)為二進(jìn)制:1011111001010100010000101110100
  2. 將小數(shù)部分轉(zhuǎn)為二進(jìn)制:0.010111111100111111011011011101010000011000111100010111
  3. 所以其二進(jìn)制拼接后為:1011111001010100010000101110100.010111111100111111011011011101010000011000111100010111漾稀,但顯然位數(shù)超出了64位的限制模闲,而且小數(shù)點也不可能存儲的為小數(shù)點(只有0和1啊)
  4. 所以將小數(shù)點左移30位后轉(zhuǎn)為科學(xué)計數(shù)法:1.011111001010100010000101110100010111111100111111011011011101010000011000111100010111 * 2^30
  5. 正數(shù)崭捍,符號位為0尸折,我們在最高位符號位中填0
  6. 指數(shù)部分,通過左移得到的殷蛇,指數(shù)為正实夹,因此62位填1,然后將指數(shù)30-1=29粒梦,二進(jìn)制為101001亮航,在左邊添0,所以61~52位湊夠了10位匀们,因此指數(shù)部分為100 0010 1001
  7. 至于尾數(shù)部分缴淋,直接將科學(xué)計數(shù)法后小數(shù)點后面的數(shù)扔進(jìn)去即可(因為超出52位長度,所以更多的位數(shù)會舍去,最后一位會0舍1入)重抖,所以尾數(shù)部分為:0111110010101000100001011101000101111111001111110111
  8. 至此露氮,這個浮點數(shù)的二進(jìn)制就存儲為:0100 0010 1001 0111 1100 1010 1000 1000 0101 1101 0001 0111 1111 0011 1111 0111,轉(zhuǎn)為16進(jìn)制為:0x4297CA885D17F3F7
番外篇:JS中的精度丟失

說到這里就不得不簡單提一下數(shù)字精度丟失的問題钟沛。上面也知道畔规,JS中所有的數(shù)字都是用double方式進(jìn)行存儲的,所以必然會存在精度丟失問題讹剔。

以下轉(zhuǎn)自文章:JavaScript數(shù)字精度丟失問題總結(jié)

此時只能模仿十進(jìn)制進(jìn)行四舍五入了油讯,但是二進(jìn)制只有 0 和 1 兩個,于是變?yōu)?0 舍 1 入延欠。這即是計算機中部分浮點數(shù)運算時出現(xiàn)誤差陌兑,丟失精度的根本原因。

大整數(shù)的精度丟失和浮點數(shù)本質(zhì)上是一樣的由捎,尾數(shù)位最大是 52 位兔综,因此 JS 中能精準(zhǔn)表示的最大整數(shù)是 Math.pow(2, 53),十進(jìn)制即 9007199254740992

大于9007199254740992的可能會丟失精度:
9007199254740992 >> 10000000000000...000 ``// 共計 53 個 0
9007199254740992 + 1 >> 10000000000000...001 ``// 中間 52 個 0
9007199254740992 + 2 >> 10000000000000...010 ``// 中間 51 個 0

實際上
9007199254740992 + 1 ``// 丟失
9007199254740992 + 2 ``// 未丟失
9007199254740992 + 3 ``// 丟失
9007199254740992 + 4 ``// 未丟失

以上狞玛,可以知道看似有窮的數(shù)字, 在計算機的二進(jìn)制表示里卻是無窮的软驰,由于存儲位數(shù)限制因此存在“舍去”,精度丟失就發(fā)生了心肪。

想了解更深入的分析可以看這篇論文(你品锭亏!你細(xì)品!):What Every Computer Scientist Should Know About Floating-Point Arithmetic
關(guān)于精度和范圍的內(nèi)容可查看【JS的數(shù)值精度和數(shù)值范圍】

番外篇2:JS中的位運算數(shù)據(jù)異常

位運算只對整數(shù)起作用硬鞍,如果一個運算子不是整數(shù)慧瘤,會自動轉(zhuǎn)為整數(shù)后再運行。雖然在 JavaScript 內(nèi)部固该,數(shù)值都是以64位浮點數(shù)的形式儲存锅减,但是做位運算的時候,是以32位帶符號的整數(shù)進(jìn)行運算的伐坏,并且返回值也是一個32位帶符號的整數(shù)怔匣。

ECMAScript 中,所有整數(shù)字面量默認(rèn)都是有符號整數(shù)桦沉,這意味著什么呢每瞒?有符號整數(shù)使用 31 位表示整數(shù)的數(shù)值,用第 32 位表示整數(shù)的符號纯露,0 表示正數(shù)独泞,1 表示負(fù)數(shù)。數(shù)值范圍從-2147483648 到 2147483647苔埋。

這也就是為什么對于整數(shù)部位為10位的時間戳懦砂,通過位運算可以進(jìn)行取整(因為目前時間戳159xxxxxxx<2147483647),不存在時間戳超過范圍的問題。但是對于13位時間戳荞膘,如1596615447123>2147483647罚随,此時再通過位運算操作的時候就會導(dǎo)致異常蝌借,如:

let t = 1596615447015.007
console.log(Math.trunc(t), Math.trunc(t / 1000)) // 1596615447015 1596615447
console.log(t / 1000 | 0) // 1596615447
console.log(t | 0) // -1112387097

這主要是因為在進(jìn)行位運算之前痊班,JS會先將64bit的浮點數(shù)1596615447015.01轉(zhuǎn)為32bit的有符號整型后進(jìn)行運算的,這個轉(zhuǎn)換過程如下:

32bit整型存儲結(jié)構(gòu)
  1. 首先1596615447015.333的二進(jìn)制表示為10111001110111101101100100101000111100111.0101010101,其在內(nèi)存中的存儲結(jié)構(gòu)如下:
    1. 正數(shù)霜幼,最高位符號位0
    2. 科學(xué)計數(shù)法小數(shù)點左移屠升,指數(shù)位最高位為1
    3. 小數(shù)點左移40位潮改,則剩余指數(shù)部分為40-1=39的10位二進(jìn)制00 0010 0111
    4. 所以前12位為0100 0010 0111
  2. 剩余52位從小數(shù)點后開始取52位(不足52位在最后補0,超過則最后一位0舍1入)為0111001110111101101100100101000111100111010101010100
  3. 所以1596615447015.333的二進(jìn)制存儲表示為:0100 0010 0111 0111 0011 1011 1101 1011 0010 0101 0001 1110 0111 0101 0101 0100腹暖,轉(zhuǎn)為16進(jìn)制表示為:0x42773BDB251E7554
  4. 開始將其轉(zhuǎn)為32bit的int類型汇在,首先根據(jù)指數(shù)位100 0010 0111可知,小數(shù)點右移39+1=40位脏答,剩余小數(shù)位數(shù)舍掉糕殉,則52位尾數(shù)部分得到的是73BDB251E7,即二進(jìn)制表示為0111 0011 1011 1101 1011 0010 0101 0001 1110 0111
  5. 截取上面二進(jìn)制的后32位得到:1011 1101 1011 0010 0101 0001 1110 0111殖告,系統(tǒng)會將這32位數(shù)當(dāng)作轉(zhuǎn)換后的int類型阿蝶,由于最高位為1,即這是一個負(fù)數(shù)
  6. 對于系統(tǒng)來說黄绩,如果是負(fù)數(shù)羡洁,則用這個負(fù)數(shù)的補碼表示,即這個負(fù)數(shù)絕對值的二進(jìn)制按位取反爽丹,然后最后一位執(zhí)行不進(jìn)位+1的來的筑煮,所以對于上面這個二進(jìn)制,將其轉(zhuǎn)為10進(jìn)制的過程如下:
    1. 最高位符號位為1习劫,表示負(fù)數(shù)
    2. 既然是負(fù)數(shù),最后一位不退位-1嚼隘,得到:011 1101 1011 0010 0101 0001 1110 0110
    3. 取補碼:100 0010 0100 1101 1010 1110 0001 1001
    4. 表示為十進(jìn)制:-1112387097
  7. 至此诽里,就可以解釋為什么1596615447015.333 | 0 = -1112387097了。

為了驗證上述過程飞蛹,我們再舉一個例子:1590015447015.123 >> 0 = 877547495

  1. 1590015447015.123的二進(jìn)制表示為:10111001000110100010011100100111111100111.000111111
  2. 舍去其小數(shù)部分后谤狡,從后往前取32位為:00110100010011100100111111100111
  3. 最高位為0,正數(shù)卧檐,直接轉(zhuǎn)為10進(jìn)制為:877547495

將將將將墓懂!沒錯的吧!所以JS的這個坑還真是霉囚。捕仔。。 讓人無語

回歸正題

經(jīng)過上面的一番折騰,我們知道了超過10位的時間戳(實際上是大于2^32的數(shù))榜跌,通過位運算都會導(dǎo)致數(shù)據(jù)異常闪唆,所以對于通過位運算對時間戳取整,我們還是需要先將其改為10位時間戳后再取整才可以钓葫,廢話不多說悄蕾,直接上代碼:

const performance = require('perf_hooks').performance;

let s, e, interval = 1000000000

console.log(`\n\n執(zhí)行${interval}次速度對比:====================================`)

let a = (performance.timeOrigin + performance.now()) / 1000

s = process.uptime()
for (let i = 0; i < interval; i++) Math.floor(a)
e = process.uptime()
console.log('Math.floor', a, Math.floor(a), e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) Math.trunc(a)
e = process.uptime()
console.log('Math.trunc', a, Math.trunc(a), e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) a >> 0
e = process.uptime()
console.log('X>>0', a, a >> 0, e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) a << 0
e = process.uptime()
console.log('X<<0', a, a << 0, e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) a | 0
e = process.uptime()
console.log('X|0', a, a | 0, e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) ~~a
e = process.uptime()
console.log('~~X', a, ~~a, e - s)

得到的結(jié)果:

執(zhí)行1000000000次速度對比:====================================
Math.floor 1596625611.8681817 1596625611 0.9910000000000001
Math.trunc 1596625611.8681817 1596625611 0.9850000000000001
X>>0 1596625611.8681817 1596625611 0.649
X<<0 1596625611.8681817 1596625611 0.6599999999999997
X|0 1596625611.8681817 1596625611 0.6659999999999995
~~X 1596625611.8681817 1596625611 0.6550000000000002

是不是很驚喜!4「 帆调!位運算的效率果然會領(lǐng)先于Math

至此,我們一直找到了最快獲取時間戳和最快取整的兩個手段了豆同,分別是通過performance庫和>>等位運算實現(xiàn)番刊。那是不是還有優(yōu)化的空間呢?再回過頭來看一下我們的業(yè)務(wù)代碼:

const performance = require('perf_hooks').performance;

let s, e, interval = 100000000

console.log(`\n\n執(zhí)行${interval}次速度對比:====================================`)

s = process.uptime()
for (let i = 0; i < interval; i++) getTimestamp1()
e = process.uptime()
console.log('getTimestamp1', getTimestamp1(), e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) getTimestamp2()
e = process.uptime()
console.log('getTimestamp2', getTimestamp2(), e - s)

s = process.uptime()
for (let i = 0; i < interval; i++) getTimestamp3()
e = process.uptime()
console.log('getTimestamp3', getTimestamp3(), e - s)


function getTimestamp1() {
    return (performance.timeOrigin + performance.now()) / 1000 >> 0
}

function getTimestamp2() {
    return (performance.timeOrigin / 1000 >> 0) + (performance.now() / 1000 >> 0)
}

function getTimestamp3() {
    return Math.trunc((performance.timeOrigin + performance.now()) / 1000)
}

運行結(jié)果:

執(zhí)行100000000次速度對比:====================================
getTimestamp1 1596628296 4.924
getTimestamp2 1596628301 5.109
getTimestamp3 1596628306 5.022
  • 歸納總結(jié)

  1. 對于獲取系統(tǒng)時間來說诱告,通過performance實現(xiàn)性能最高
  2. 對于取整運算來說撵枢,位運算的效率最高
  3. 盡可能減少除法的使用,因為它效率最慢

所以精居,獲取系統(tǒng)10位時間戳最快的方式就是下面這一句:

const performance = require('perf_hooks').performance;
(performance.timeOrigin + performance.now()) / 1000 >> 0
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锄禽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子靴姿,更是在濱河造成了極大的恐慌沃但,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佛吓,死亡現(xiàn)場離奇詭異宵晚,居然都是意外死亡,警方通過查閱死者的電腦和手機维雇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門淤刃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吱型,你說我怎么就攤上這事逸贾。” “怎么了津滞?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵铝侵,是天一觀的道長。 經(jīng)常有香客問我触徐,道長咪鲜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任撞鹉,我火速辦了婚禮疟丙,結(jié)果婚禮上颖侄,老公的妹妹穿的比我還像新娘。我一直安慰自己隆敢,他們只是感情好发皿,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拂蝎,像睡著了一般穴墅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上温自,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天玄货,我揣著相機與錄音,去河邊找鬼悼泌。 笑死松捉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的馆里。 我是一名探鬼主播隘世,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鸠踪!你這毒婦竟也來了丙者?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤营密,失蹤者是張志新(化名)和其女友劉穎械媒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體评汰,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡纷捞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了被去。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片主儡。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖惨缆,靈堂內(nèi)的尸體忽然破棺而出糜值,到底是詐尸還是另有隱情,我是刑警寧澤踪央,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布臀玄,位于F島的核電站瓢阴,受9級特大地震影響畅蹂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荣恐,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一液斜、第九天 我趴在偏房一處隱蔽的房頂上張望累贤。 院中可真熱鬧,春花似錦少漆、人聲如沸臼膏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽渗磅。三九已至,卻和暖如春检访,著一層夾襖步出監(jiān)牢的瞬間始鱼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工脆贵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留医清,地道東北人。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓卖氨,卻偏偏與公主長得像会烙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子筒捺,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355