Asynchronous 在F中异步处理来自streamReader的数据#

Asynchronous 在F中异步处理来自streamReader的数据#,asynchronous,f#,streamreader,Asynchronous,F#,Streamreader,关于,我怀疑它是否等同于向每个线程传递一个Seq的切片块,以及它是否能够安全地处理并行性;它是StreamReader线程安全的吗 下面是我用来测试这一点的代码(欢迎对使用的模式提出任何建议或批评:) nthreads=4 让数据=seq{ 使用sr=new System.IO.StreamReader(文件路径) 而不是sr.EndOfStream 收益率sr.ReadLine() } 设长度=(数据|>序号长度) 让packSize=长度/n读取 让小组= [对于0中的i…(n读取数-1)-

关于,我怀疑它是否等同于向每个线程传递一个Seq的切片块,以及它是否能够安全地处理并行性;它是StreamReader线程安全的吗

下面是我用来测试这一点的代码(欢迎对使用的模式提出任何建议或批评:)

nthreads=4
让数据=seq{
使用sr=new System.IO.StreamReader(文件路径)
而不是sr.EndOfStream
收益率sr.ReadLine()
}
设长度=(数据|>序号长度)
让packSize=长度/n读取
让小组=
[对于0中的i…(n读取数-1)->如果iSeq.skip(packSize*i)
|>Seq.take(包装尺寸)
else Data |>Seq.skip(packSize*i)]
设f=一些修改数据的复函数
seq{for a in group->f a}
|>异步并行
|>异步运行

您的
数据
值的类型为
seq
,这意味着它是惰性的。这意味着,当您执行访问它的某些计算时,延迟序列将创建
StreamReader
的新实例,并独立于其他计算读取数据

当您将一些打印添加到
seq{..}
块时,您可以很容易地看到这一点:

let Data = seq {
    printfn "reading"
    use sr = new System.IO.StreamReader (filePath)
    while not sr.EndOfStream do
        yield sr.ReadLine ()  }
因此,您的并行处理实际上很好。它将为每个并行线程创建一个新的计算,因此永远不会共享
StreamReader
实例


另一个问题是,这是否真的是一件有用的事情——从磁盘读取数据通常是一个瓶颈,因此在一个循环中执行操作可能会更快。即使这样做有效,使用
Seq.length
获取长度也是一种缓慢的方法(因为它需要读取整个文件),对于
skip
也是如此。更好(但更复杂)的解决方案可能是使用stream
Seek

,根据“任何[StreamReader]的公共静态成员都是线程安全的。任何实例成员都不能保证是线程安全的。”因为
ReadLine
是一种实例方法,不能保证它是线程安全的。但是在这种情况下,它应该是无关的,因为
是一个列表,并且在这里不是并行计算的。哇,谢谢你的评论。实际上,每个线程中的计算都非常复杂,涉及一些需要缓存的副作用,所以我必须在这里考虑权衡。
let Data = seq {
    printfn "reading"
    use sr = new System.IO.StreamReader (filePath)
    while not sr.EndOfStream do
        yield sr.ReadLine ()  }