从 F# 中特定位置的二进制文件读取整数的性能问题

2024-01-09

今天早上我问here https://stackoverflow.com/questions/24381090/performance-issue-with-reading-integers-from-a-binary-file-at-specific-locations为什么我的 Python 代码比我的 F# 版本慢很多,但我想知道 F# 版本是否可以变得更快。我有什么想法可以创建以下代码的更快版本,从具有 32 位整数的二进制文件中读取唯一索引的排序列表?请注意,我尝试了两种方法,一种基于 BinaryReader,另一种基于 MemoryMappedFile (以及 Github 上的更多内容 https://github.com/samuelbosch/blogbits/blob/master/geosrc/AsciiToBin.fsx).

module SimpleRead            
    let readValue (reader:BinaryReader) cellIndex = 
        // set stream to correct location
        reader.BaseStream.Position <- cellIndex*4L
        match reader.ReadInt32() with
        | Int32.MinValue -> None
        | v -> Some(v)

    let readValues fileName indices = 
        use reader = new BinaryReader(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
        // Use list or array to force creation of values (otherwise reader gets disposed before the values are read)
        let values = List.map (readValue reader) (List.ofSeq indices)
        values

module MemoryMappedSimpleRead =

    open System.IO.MemoryMappedFiles

    let readValue (reader:MemoryMappedViewAccessor) offset cellIndex =
        let position = (cellIndex*4L) - offset
        match reader.ReadInt32(position) with
        | Int32.MinValue -> None
        | v -> Some(v)

    let readValues fileName indices =
        use mmf = MemoryMappedFile.CreateFromFile(fileName, FileMode.Open)
        let offset = (Seq.min indices ) * 4L
        let last = (Seq.max indices) * 4L
        let length = 4L+last-offset
        use reader = mmf.CreateViewAccessor(offset, length, MemoryMappedFileAccess.Read)
        let values = (List.ofSeq indices) |> List.map (readValue reader offset)
        values

为了进行比较,这里是我最新的 numpy 版本

import numpy as np

def convert(v):
    if v <> -2147483648:
        return v
    else:
        return None

def read_values(filename, indices):
    values_arr = np.memmap(filename, dtype='int32', mode='r')
    return map(convert, values_arr[indices])

Update与我之前所说的相反,我的 python 仍然比 F# 版本慢很多,但由于我的 python 测试中的错误,它看起来并非如此。 将此问题留在这里,以防对 BinaryReader 或 MemoryMappedFile 有深入了解的人知道一些改进。


通过使用 reader.BaseStream.Seek 而不是 reader.BaseStream.Position,我设法使 SimpleReader 速度提高了 30%。我还用数组替换了列表,但这并没有改变很多。

我的简单阅读器的完整代码现在是:

open System
open System.IO

let readValue (reader:BinaryReader) cellIndex = 
    // set stream to correct location
    reader.BaseStream.Seek(int64 (cellIndex*4), SeekOrigin.Begin) |> ignore
    match reader.ReadInt32() with
    | Int32.MinValue -> None
    | v -> Some(v)

let readValues indices fileName = 
    use reader = new BinaryReader(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
    // Use list or array to force creation of values (otherwise reader gets disposed before the values are read)
    let values = Array.map (readValue reader) indices
    values

完整代码和其他语言版本位于GitHub https://github.com/samuelbosch/blogbits/tree/master/geosrc/binreaders.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 F# 中特定位置的二进制文件读取整数的性能问题 的相关文章

随机推荐