在 F# 中找不到此日期时间测试失败的原因
Can't find why this datetime test fails, in F#
我有以下功能,是在一些人的帮助下制作的:
module DateTimeFormatter =
let mutable year = -1
let mutable month = -1
let mutable day = -1
let mutable hour = -1
let mutable minute = -1
let mutable second = -1
let dateTimeArray = "xxxx-xx-xx xx:xx:xx.xxx".ToCharArray()
let timeArray = "xx:xx:xx.xxx".ToCharArray()
let zeroChar = int '0'
// format the datetime into a date and a time with milliseconds
let format (dateTime: DateTime) =
if dateTime.Year <> year then
year <- dateTime.Year
dateTimeArray.[0] <- char (zeroChar + year / 1000)
dateTimeArray.[1] <- char (zeroChar + (year % 1000) / 100)
dateTimeArray.[2] <- char (zeroChar + (year % 100) / 10)
dateTimeArray.[3] <- char (zeroChar + (year % 10))
if dateTime.Month <> month then
month <- dateTime.Month
dateTimeArray.[5] <- char (zeroChar + month / 10)
dateTimeArray.[6] <- char (zeroChar + month % 10)
if dateTime.Day <> day then
day <- dateTime.Day
dateTimeArray.[8] <- char (zeroChar + day / 10)
dateTimeArray.[9] <- char (zeroChar + day % 10)
if dateTime.Hour <> hour then
hour <- dateTime.Hour
dateTimeArray.[11] <- char (zeroChar + hour / 10)
dateTimeArray.[12] <- char (zeroChar + hour % 10)
if dateTime.Minute <> minute then
minute <- dateTime.Minute
dateTimeArray.[14] <- char (zeroChar + minute / 10)
dateTimeArray.[15] <- char (zeroChar + minute % 10)
if dateTime.Second <> second then
second <- dateTime.Second
dateTimeArray.[17] <- char (zeroChar + second / 10)
dateTimeArray.[18] <- char (zeroChar + second % 10)
let ms = dateTime.Millisecond
dateTimeArray.[20] <- char (zeroChar + ms / 100)
dateTimeArray.[21] <- char (zeroChar + (ms % 100) / 10)
dateTimeArray.[22] <- char (zeroChar + ms % 10)
new string(dateTimeArray)
想法是尽可能快地构建日期时间+毫秒时间戳。
但有时,但并非总是如此,我得到以下输出:
2021-06-01 xx:xx:53.648
并且故障总是在小时/分钟上,但有时它工作正常,有时它不工作。并且在构建字符串时我没有发现测试有任何问题,但由于占位符 'x' 就位,因此即使是第一次测试,小时和分钟似乎也失败了。
可能是这些超级简单的事情之一需要另一双眼睛才能看到:)
它失败了,因为模块中的可变变量和 dateTimeArray
正在从不同的线程遍历。这不是线程安全代码。
我发布了一些评论,现在我已经删除了,因为我看代码的时间不够长,无法理解其意图。意图显然是要优化,但它失败了。简化功能实际上会提高性能。额外的逻辑和额外的变量都没有帮助,它们中的任何一个。下面这段代码仍然更快。
我有点怀疑线程本地存储能否帮助原始代码击败此代码,因为我认为在该逻辑中找不到任何性能优势。我认为 DateTime.ToString
的好处在于这个简化代码中剩下的内容:
let dateTimeArray = "xxxx-xx-xx xx:xx:xx.xxx".ToCharArray()
let [<Literal>] zeroChar = 48 // '0'
let format (dateTime: DateTime) =
let dateTimeArray = Array.copy dateTimeArray
dateTimeArray.[0] <- char (zeroChar + dateTime.Year / 1000)
dateTimeArray.[1] <- char (zeroChar + (dateTime.Year % 1000) / 100)
dateTimeArray.[2] <- char (zeroChar + (dateTime.Year % 100) / 10)
dateTimeArray.[3] <- char (zeroChar + (dateTime.Year % 10))
dateTimeArray.[5] <- char (zeroChar + dateTime.Month / 10)
dateTimeArray.[6] <- char (zeroChar + dateTime.Month % 10)
dateTimeArray.[8] <- char (zeroChar + dateTime.Day / 10)
dateTimeArray.[9] <- char (zeroChar + dateTime.Day % 10)
dateTimeArray.[11] <- char (zeroChar + dateTime.Hour / 10)
dateTimeArray.[12] <- char (zeroChar + dateTime.Hour % 10)
dateTimeArray.[14] <- char (zeroChar + dateTime.Minute / 10)
dateTimeArray.[15] <- char (zeroChar + dateTime.Minute % 10)
dateTimeArray.[17] <- char (zeroChar + dateTime.Second / 10)
dateTimeArray.[18] <- char (zeroChar + dateTime.Second % 10)
dateTimeArray.[20] <- char (zeroChar + dateTime.Millisecond / 100)
dateTimeArray.[21] <- char (zeroChar + (dateTime.Millisecond % 100) / 10)
dateTimeArray.[22] <- char (zeroChar + dateTime.Millisecond % 10)
new string(dateTimeArray)
多次读取 dateTime
的属性不会降低函数速度。读取 属性 一次,例如读取 dateTime.Year
一次到局部值然后在四个地方使用它,实际上会使函数变慢。
看起来这样可以节省更多时间,并且不再需要外部 dateTimeArray
:
let dateTimeArray: char[] =
[|
char (zeroChar + dateTime.Year / 1000)
char (zeroChar + (dateTime.Year % 1000) / 100)
char (zeroChar + (dateTime.Year % 100) / 10)
char (zeroChar + (dateTime.Year % 10))
'-'
char (zeroChar + dateTime.Month / 10)
char (zeroChar + dateTime.Month % 10)
'-'
char (zeroChar + dateTime.Day / 10)
char (zeroChar + dateTime.Day % 10)
' '
char (zeroChar + dateTime.Hour / 10)
char (zeroChar + dateTime.Hour % 10)
':'
char (zeroChar + dateTime.Minute / 10)
char (zeroChar + dateTime.Minute % 10)
':'
char (zeroChar + dateTime.Second / 10)
char (zeroChar + dateTime.Second % 10)
'.'
char (zeroChar + dateTime.Millisecond / 100)
char (zeroChar + (dateTime.Millisecond % 100) / 10)
char (zeroChar + dateTime.Millisecond % 10)
|]
我还有一个版本。 Math.DivRem
的使用似乎稍微减少了一些,但是查找数组 digits
增加了时间,尽管它带来了一些优雅。
let format (dateTime: DateTime) =
let monthHigh, monthLow = Math.DivRem (dateTime.Month, 10)
let dayHigh, dayLow = Math.DivRem (dateTime.Day, 10)
let hourHigh, hourLow = Math.DivRem (dateTime.Hour, 10)
let minuteHigh, minuteLow = Math.DivRem (dateTime.Minute, 10)
let secondHigh, secondLow = Math.DivRem (dateTime.Second, 10)
let digit = [| '0'; '1'; '2'; '3'; '4'; '5'; '6'; '7'; '8'; '9' |]
[|
digit.[dateTime.Year / 1000]
digit.[(dateTime.Year % 1000) / 100]
digit.[(dateTime.Year % 100) / 10]
digit.[dateTime.Year % 10]
'-'
digit.[monthHigh]
digit.[monthLow]
'-'
digit.[dayHigh]
digit.[dayLow]
' '
digit.[hourHigh]
digit.[hourLow]
':'
digit.[minuteHigh]
digit.[minuteLow]
':'
digit.[secondHigh]
digit.[secondLow]
'.'
digit.[dateTime.Millisecond / 100]
digit.[(dateTime.Millisecond % 100) / 10]
digit.[dateTime.Millisecond % 10]
|] |> (fun a -> new String(a))
我有以下功能,是在一些人的帮助下制作的:
module DateTimeFormatter =
let mutable year = -1
let mutable month = -1
let mutable day = -1
let mutable hour = -1
let mutable minute = -1
let mutable second = -1
let dateTimeArray = "xxxx-xx-xx xx:xx:xx.xxx".ToCharArray()
let timeArray = "xx:xx:xx.xxx".ToCharArray()
let zeroChar = int '0'
// format the datetime into a date and a time with milliseconds
let format (dateTime: DateTime) =
if dateTime.Year <> year then
year <- dateTime.Year
dateTimeArray.[0] <- char (zeroChar + year / 1000)
dateTimeArray.[1] <- char (zeroChar + (year % 1000) / 100)
dateTimeArray.[2] <- char (zeroChar + (year % 100) / 10)
dateTimeArray.[3] <- char (zeroChar + (year % 10))
if dateTime.Month <> month then
month <- dateTime.Month
dateTimeArray.[5] <- char (zeroChar + month / 10)
dateTimeArray.[6] <- char (zeroChar + month % 10)
if dateTime.Day <> day then
day <- dateTime.Day
dateTimeArray.[8] <- char (zeroChar + day / 10)
dateTimeArray.[9] <- char (zeroChar + day % 10)
if dateTime.Hour <> hour then
hour <- dateTime.Hour
dateTimeArray.[11] <- char (zeroChar + hour / 10)
dateTimeArray.[12] <- char (zeroChar + hour % 10)
if dateTime.Minute <> minute then
minute <- dateTime.Minute
dateTimeArray.[14] <- char (zeroChar + minute / 10)
dateTimeArray.[15] <- char (zeroChar + minute % 10)
if dateTime.Second <> second then
second <- dateTime.Second
dateTimeArray.[17] <- char (zeroChar + second / 10)
dateTimeArray.[18] <- char (zeroChar + second % 10)
let ms = dateTime.Millisecond
dateTimeArray.[20] <- char (zeroChar + ms / 100)
dateTimeArray.[21] <- char (zeroChar + (ms % 100) / 10)
dateTimeArray.[22] <- char (zeroChar + ms % 10)
new string(dateTimeArray)
想法是尽可能快地构建日期时间+毫秒时间戳。
但有时,但并非总是如此,我得到以下输出:
2021-06-01 xx:xx:53.648
并且故障总是在小时/分钟上,但有时它工作正常,有时它不工作。并且在构建字符串时我没有发现测试有任何问题,但由于占位符 'x' 就位,因此即使是第一次测试,小时和分钟似乎也失败了。
可能是这些超级简单的事情之一需要另一双眼睛才能看到:)
它失败了,因为模块中的可变变量和 dateTimeArray
正在从不同的线程遍历。这不是线程安全代码。
我发布了一些评论,现在我已经删除了,因为我看代码的时间不够长,无法理解其意图。意图显然是要优化,但它失败了。简化功能实际上会提高性能。额外的逻辑和额外的变量都没有帮助,它们中的任何一个。下面这段代码仍然更快。
我有点怀疑线程本地存储能否帮助原始代码击败此代码,因为我认为在该逻辑中找不到任何性能优势。我认为 DateTime.ToString
的好处在于这个简化代码中剩下的内容:
let dateTimeArray = "xxxx-xx-xx xx:xx:xx.xxx".ToCharArray()
let [<Literal>] zeroChar = 48 // '0'
let format (dateTime: DateTime) =
let dateTimeArray = Array.copy dateTimeArray
dateTimeArray.[0] <- char (zeroChar + dateTime.Year / 1000)
dateTimeArray.[1] <- char (zeroChar + (dateTime.Year % 1000) / 100)
dateTimeArray.[2] <- char (zeroChar + (dateTime.Year % 100) / 10)
dateTimeArray.[3] <- char (zeroChar + (dateTime.Year % 10))
dateTimeArray.[5] <- char (zeroChar + dateTime.Month / 10)
dateTimeArray.[6] <- char (zeroChar + dateTime.Month % 10)
dateTimeArray.[8] <- char (zeroChar + dateTime.Day / 10)
dateTimeArray.[9] <- char (zeroChar + dateTime.Day % 10)
dateTimeArray.[11] <- char (zeroChar + dateTime.Hour / 10)
dateTimeArray.[12] <- char (zeroChar + dateTime.Hour % 10)
dateTimeArray.[14] <- char (zeroChar + dateTime.Minute / 10)
dateTimeArray.[15] <- char (zeroChar + dateTime.Minute % 10)
dateTimeArray.[17] <- char (zeroChar + dateTime.Second / 10)
dateTimeArray.[18] <- char (zeroChar + dateTime.Second % 10)
dateTimeArray.[20] <- char (zeroChar + dateTime.Millisecond / 100)
dateTimeArray.[21] <- char (zeroChar + (dateTime.Millisecond % 100) / 10)
dateTimeArray.[22] <- char (zeroChar + dateTime.Millisecond % 10)
new string(dateTimeArray)
多次读取 dateTime
的属性不会降低函数速度。读取 属性 一次,例如读取 dateTime.Year
一次到局部值然后在四个地方使用它,实际上会使函数变慢。
看起来这样可以节省更多时间,并且不再需要外部 dateTimeArray
:
let dateTimeArray: char[] =
[|
char (zeroChar + dateTime.Year / 1000)
char (zeroChar + (dateTime.Year % 1000) / 100)
char (zeroChar + (dateTime.Year % 100) / 10)
char (zeroChar + (dateTime.Year % 10))
'-'
char (zeroChar + dateTime.Month / 10)
char (zeroChar + dateTime.Month % 10)
'-'
char (zeroChar + dateTime.Day / 10)
char (zeroChar + dateTime.Day % 10)
' '
char (zeroChar + dateTime.Hour / 10)
char (zeroChar + dateTime.Hour % 10)
':'
char (zeroChar + dateTime.Minute / 10)
char (zeroChar + dateTime.Minute % 10)
':'
char (zeroChar + dateTime.Second / 10)
char (zeroChar + dateTime.Second % 10)
'.'
char (zeroChar + dateTime.Millisecond / 100)
char (zeroChar + (dateTime.Millisecond % 100) / 10)
char (zeroChar + dateTime.Millisecond % 10)
|]
我还有一个版本。 Math.DivRem
的使用似乎稍微减少了一些,但是查找数组 digits
增加了时间,尽管它带来了一些优雅。
let format (dateTime: DateTime) =
let monthHigh, monthLow = Math.DivRem (dateTime.Month, 10)
let dayHigh, dayLow = Math.DivRem (dateTime.Day, 10)
let hourHigh, hourLow = Math.DivRem (dateTime.Hour, 10)
let minuteHigh, minuteLow = Math.DivRem (dateTime.Minute, 10)
let secondHigh, secondLow = Math.DivRem (dateTime.Second, 10)
let digit = [| '0'; '1'; '2'; '3'; '4'; '5'; '6'; '7'; '8'; '9' |]
[|
digit.[dateTime.Year / 1000]
digit.[(dateTime.Year % 1000) / 100]
digit.[(dateTime.Year % 100) / 10]
digit.[dateTime.Year % 10]
'-'
digit.[monthHigh]
digit.[monthLow]
'-'
digit.[dayHigh]
digit.[dayLow]
' '
digit.[hourHigh]
digit.[hourLow]
':'
digit.[minuteHigh]
digit.[minuteLow]
':'
digit.[secondHigh]
digit.[secondLow]
'.'
digit.[dateTime.Millisecond / 100]
digit.[(dateTime.Millisecond % 100) / 10]
digit.[dateTime.Millisecond % 10]
|] |> (fun a -> new String(a))