【发布时间】:2021-03-16 10:37:31
【问题描述】:
我对 F# 中序列表达式的内部工作感到有些困惑。
通常,如果我们使用 seq 制作一个顺序文件读取器,而不是有意缓存数据
seq {
let mutable current = file.Read()
while current <> -1 do
yield current
}
如果我们尝试做一些重复或回溯,我们最终会出现一些奇怪的行为,我的想法是,因为 Read() 是一个调用一些可变值的函数,我们不能期望输出是正确的如果我们重新迭代。但是,即使在边界读取上,这也表现得很好?
let Read path =
seq {
use fp = System.IO.File.OpenRead path
let buf = [| for _ in 0 .. 1024 -> 0uy |]
let mutable pos = 1
let mutable current = 0
while pos <> 0 do
if current = 0 then
pos <- fp.Read(buf, 0, 1024)
if pos > 0 && current < pos then
yield buf.[current]
current <- (current + 1) % 1024
}
let content = Read "some path"
我们显然使用相同的缓冲区来提高性能,但是假设我们读取 1025 字节,它将触发对缓冲区的更新,如果我们在仍然获得正确输出后尝试读取位置
【问题讨论】:
-
你如何重新迭代或回溯
seq? -
FileStream已被缓冲。来自docs:FileStream 缓冲输入和输出以获得更好的性能。如果你有一个没有缓冲的流,你可以将它包装在BufferedStream中,它会是。但是你能解释一下你想在这里做什么吗? 如果我们尝试进行一些重新迭代或回溯,我们最终会出现一些奇怪的行为会令人困惑,因为序列不能倒带或随机访问。 -
@Sebastian, 例如 let s = Read "some path";让 s_1024 = Seq.skip 1024 秒; let s_1025 = Seq.tail s_1024 以上适用于同一序列的不同实例,它们也将属于不同的缓冲区。如下所述,我在获得相同值时看到一些“奇怪”的东西的原因是文件流的范围。我正在实现一个“持久”文件阅读器,它可以作为一个序列传递以方便。它的使用会读到某个点,然后如上所示回溯,但要大一点。
-
具有持久的含义,假设没有其他线程同时写入文件,我们将在序列的相同位置得到相同的输出