gpt4 book ai didi

optimization - 如何在 F# 中优化此代码以提高速度,以及为什么一个部分执行两次?

转载 作者:行者123 更新时间:2023-12-04 14:43:56 29 4
gpt4 key购买 nike

该代码用于将历史财务数据打包成 16 个字节:

type PackedCandle =
struct
val H: single
val L: single
val C: single
val V: int
end
new(h: single, l: single, c: single, v: int) = { H = h; L = l; C = c; V = v }
member this.ToByteArray =
let a = Array.create 16 (byte 0)
let h = BitConverter.GetBytes(this.H)
let l = BitConverter.GetBytes(this.L)
let c = BitConverter.GetBytes(this.C)
let v = BitConverter.GetBytes(this.V)
a.[00] <- h.[0]; a.[01] <- h.[1]; a.[02] <- h.[2]; a.[03] <- h.[3]
a.[04] <- l.[0]; a.[05] <- l.[1]; a.[06] <- l.[2]; a.[07] <- l.[3]
a.[08] <- c.[0]; a.[09] <- c.[1]; a.[10] <- c.[2]; a.[11] <- c.[3]
a.[12] <- v.[0]; a.[13] <- v.[1]; a.[14] <- v.[2]; a.[15] <- v.[3]
printfn "!!" <- for the second part of the question
a

这些数组是通过网络发送的,因此我需要数据尽可能小,但由于这是同时跟踪大约 80 种可交易工具,因此性能也很重要。在客户端没有获取历史数据然后更新的情况下进行了权衡,但只是每分钟获取过去 3 天的数据 block ,导致一遍又一遍地发送相同的数据以简化客户端逻辑。我继承了这个问题使低效的设计..尽可能高效。这也是通过休息轮询完成的,我现在将其转换为套接字以保持一切二进制。

所以我的第一个问题是:我怎样才能让它更快?在 C 中,你可以将任何东西转换成任何东西,我可以只取一个 float 并将其直接写入数组,所以没有什么更快的了,但在 F# 中,看起来我需要跳过箍,获取字节,然后复制它们一个由 1 而不是 4 由 4 等。有更好的方法吗?

我的第二个问题是,由于要评估一次,因此我将 ToByteArray 设为属性。我正在 Jupyter Notebook 中使用随机值进行一些测试,但随后我看到:

enter image description here

该属性似乎被执行了两次(由两个“!!”行表示)。这是为什么呢?

最佳答案

假设您有要写入的数组(通常在使用套接字时您应该使用缓冲区进行读写),您可以使用 System.Runtime.CompilerServices.Unsafe.As<TFrom, TTo> 将内存从一种类型转换为另一种类型(与 C/C++ 相同)

type PackedCandle =
// omitting fields & consructor
override c.ToString() = $"%f{c.H} %f{c.L} %f{c.C} %d{c.V}" // debug purpose

static member ReadFrom(array: byte[], offset) =
// get managed(!) pointer
// cast pointer to another type
// same as *(PackedCandle*)(&array[offset]) but safe from GC
Unsafe.As<byte, PackedCandle> &array.[offset]

member c.WriteTo(array: byte[], offset: int) =
Unsafe.As<byte, PackedCandle> &array.[offset] <- c

用法

let byteArray = Array.zeroCreate<byte> 100 // assume array come from different function

// writing
let mutable offset = 0
for i = 0 to 5 do
let candle = PackedCandle(float32 i, float32 i, float32 i, i)
candle.WriteTo(byteArray, offset)
offset <- offset + Unsafe.SizeOf<PackedCandle>() // "increment pointer"

// reading
let mutable offset = 0
for i = 0 to 5 do
let candle = PackedCandle.ReadFrom(byteArray, offset)
printfn "%O" candle
offset <- offset + Unsafe.SizeOf<PackedCandle>()

但是你真的想弄乱指针(甚至管理)吗?测出这段代码是瓶颈吗?

更新

最好使用 MemoryMarshal 而不是原始的Unsafe因为首先检查超出范围并在运行时强制使用 unmanaged(参见 herehere)类型

member c.WriteTo (array: byte[], offset: int) =
MemoryMarshal.Write(array.AsSpan(offset), &Unsafe.AsRef(&c))

static member ReadFrom (array: byte[], offset: int) =
MemoryMarshal.Read<PackedCandle>(ReadOnlySpan(array).Slice(offset))

关于optimization - 如何在 F# 中优化此代码以提高速度,以及为什么一个部分执行两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68178403/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com