如何将int写入System.Span,即int.Parse(span)的反转?

我需要编写和读取大型CSV(逗号分隔值)文件,该文件基本上包含转换为字符串的整数值。为了有效地读取此类文件,.Net Core为类型Parse引入了一种新的int方法:

public static int Parse (ReadOnlySpan<char> s,System.Globalization.NumberStyles style = 
  System.Globalization.NumberStyles.Integer,IFormatProvider provider = null);

这允许使用StreamReader将文件的字符写入字符数组。然后,我的程序必须找到分隔字符的位置,创建一个包含两个分隔符之间的字符的ReadOnlySpan,然后将其转换为int,而无需首先在其中创建string字符。由于我的文件包含数百万个值,因此避免创建数百万个strings应该会导致文件读取速度更快。我希望。

但是如何将int值作为strings写入文件?传统上,它是这样完成的:

var int1 = 1;
var int2 = 2;
streamWriter.WriteLine(int1.ToString() + "," + int2.ToString());

同样,为每个int创建一个string,然后为每行创建另一个string。这将创建数百万个需要进行垃圾回收的字符串。

我更喜欢这样的东西:

char[] charArray = getEmptyCharArray();
var span = new Span<char>(charArray);
int length1 = span.Write(int1);
charArray[length1] = ',';
span = span.Slice(length1 + 1);
int length2 = span.Write(int2);
streamWriter.Write(charArray,length1 + 1 + length2);

getEmptyCharArray()提供了可重复使用的字符数组。

不幸的是,Span没有Write()功能:-(

问题是:如何在不生成任何垃圾收集对象的情况下将int(或DateTimeDecimal或...)写入Span字符串)?

对于所有急于将问题标记为重复的人

我知道重复的问题对stackoverflow不利。但是通常一个问题被标记为重复,这实际上是不同的,因而阻止了该问题的讨论。因此,如果您认为已经有了答案,请发表评论,并给我机会进行检查。我很乐意承认该答案是否有帮助或解释,为什么它不能回答我的问题。另请注意,由于System.Span仅在.NET Core 2.1中引入,因此在2018年之前给出的答案可能都不需要。另外请注意,这里的问题是关于System.Span的,而不是HTML Span或任何其他Span。

zhang20045237 回答:如何将int写入System.Span,即int.Parse(span)的反转?

由于Ian Kent的评论,我在https://gitter.im/dotnet/corefx上提问,他们知道了答案。令人尴尬的简单:

var i = 1;
Span<char> span = new char[100];
var ok = i.TryFormat(span,out var charsWritten);

由于好几天没找到答案了,我想继续我的代码,所以我写了自己的方法,但是使用char []而不是Span。我用BenchmarkRunner测量了不同方法写入具有7'000'000 int的50 MB CSV文件的速度:

60毫秒:写入相同的常量字符串。这提供了一个基线,DotNet仅需要写入文件多长时间

for(int i = 0; i

610毫秒:使用ToString()

for(int i = 0; i

308毫秒:使用TryFormat(Span)

185毫秒:使用我自己的方法和char []

令人惊讶的是,字符串对话所花的时间比编写实际文件所花的时间长10倍。我本来希望硬盘比任何软件都要慢得多。

我们被告知Span将解决许多性能问题。不多。如果他们使用char []似乎会更好。

跨度测试代码

public void WriteTo4() {
  var PathFileName = directoryInfo.FullName + @"\Test1.csv";
  using (var fileStream = new FileStream(PathFileName,FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.None,bufferSize,FileOptions.SequentialScan)) {
    using (var streamWriter = new StreamWriter(fileStream)) {
      var lineBuffer = new char[100];
      Span<char> span = lineBuffer;
      for (int i = 0; i < iterations; i++) {
        var ok = i.TryFormat(span,out var charsWritten);
        lineBuffer[charsWritten++] = ';';
        var span1 = span[charsWritten..];
        ok = (i+1).TryFormat(span1,out charsWritten);
        span1[charsWritten++] = ';';
        span1 = span1[charsWritten..];
        ok = (i+2).TryFormat(span1,out charsWritten);
        span1[charsWritten++] = ';';
        span1 = span1[charsWritten..];
        ok = (i+3).TryFormat(span1,out charsWritten);
        span1[charsWritten++] = ';';
        span1 = span1[charsWritten..];
        ok = (i+4).TryFormat(span1,out charsWritten);
        span1[charsWritten++] = ';';
        span1 = span1[charsWritten..];
        ok = (i+5).TryFormat(span1,out charsWritten);
        span1[charsWritten++] = ';';
        span1 = span1[charsWritten..];
        ok = (i+6).TryFormat(span1,out charsWritten);
        span1[charsWritten++] = ';';

        var ca = lineBuffer[..(lineBuffer.Length - span1.Length + charsWritten)];
        streamWriter.WriteLine(lineBuffer,lineBuffer.Length - span1.Length + charsWritten);
      }
    }
  }
}

使用char []

测试代码
public void WriteTo3() {
  var PathFileName = directoryInfo.FullName + @"\Test1.csv";
  using (var fileStream = new FileStream(PathFileName,FileOptions.SequentialScan)) {
    using (var streamWriter = new StreamWriter(fileStream)) {
      var lineBuffer = new char[100];
      for (int i = 0; i < iterations; i++) {
        var index = 0;
        lineBuffer.Write3(i,ref index);
        lineBuffer[index++] = ';';
        lineBuffer.Write3(i+1,ref index);
        lineBuffer[index++] = ';';
        lineBuffer.Write3(i+2,ref index);
        lineBuffer[index++] = ';';
        lineBuffer.Write3(i+3,ref index);
        lineBuffer[index++] = ';';
        lineBuffer.Write3(i+4,ref index);
        lineBuffer[index++] = ';';
        lineBuffer.Write3(i+5,ref index);
        lineBuffer[index++] = ';';
        lineBuffer.Write3(i+6,ref index);
        lineBuffer[index++] = ';';
        streamWriter.WriteLine(lineBuffer,index);
      }
    }
  }
}


public static void Write3(this char[] charArray,int i,ref int index) {
  if (i<0) {
    charArray[index++] = '-';
    i = -i;
  }
  int start = index;

  while (i>9) {
    charArray[index++] = (char)((i % 10) + '0');
    i /= 10;
  }
  charArray[index++] = (char)(i + '0');
  var end = index-1;
  while (end>start) {
    var temp = charArray[end];
    charArray[end--] = charArray[start];
    charArray[start++] = temp;
  }
}
,

您如何尝试通过将所有数字传递来将int直接解析为char数组,将其转换为char-s并将它们直接存储到目的地。

public static ReadOnlySpan<char> ToSpan(int src)
        {
            int len = GetLength(src);
            Span<char> chars = new char[len];
            for (int i = 0; i < chars.Length; i++)
            {
                chars[i]= (char)((Math.Floor(src / Math.Pow(10,(chars.Length - i - 1))) % 10) + 48);
            }
            return chars;

            static int GetLength(int src)
            {
                int len = 0;
                while (src > 0)
                {
                    src = src / 10;
                    len++;
                }
                return len;
            }

        }
        static void Main(string[] args)
        {
            int original = 3334;
            var data = ToSpan(original);
            var copy= int.Parse(data);
            Console.WriteLine(copy);
        }

PS

  1. 糟糕的是,您需要首先在int上进行迭代才能获得目的地的长度。
  2. 您肯定可以对我从数字转换为字符的方式进行一些优化,也许还可以对数字进行分隔的方式进行优化。
本文链接:https://www.f2er.com/3147388.html

大家都在问