Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多线程文件处理_C#_Multithreading - Fatal编程技术网

C# 多线程文件处理

C# 多线程文件处理,c#,multithreading,C#,Multithreading,我想优化此代码: public static void ProcessTo(this StreamReader sr, StreamWriter sw, Action<StreamWriter, string> action, FileProcessOptions fpo = null) { if (fpo == null) { fpo = new FileProcessOptions(); }

我想优化此代码:

    public static void ProcessTo(this StreamReader sr, StreamWriter sw, Action<StreamWriter, string> action, FileProcessOptions fpo = null)
    {
        if (fpo == null)
        {
            fpo = new FileProcessOptions();
        }

        List<string> buffer = new List<string>(fpo.BuferSize);

        while (!sr.EndOfStream)
        {
            buffer.Clear();

            while (!sr.EndOfStream && buffer.Count < fpo.BuferSize)
            {
                buffer.Add(sr.ReadLine());
            }

            if (fpo.UseThreads)
            {
                buffer.AsParallel().ForAll(line => action(sw, line));
            }
            else
            {
                buffer.ForEach(line => action(sw, line));
            }
        }
    }
public static void ProcessTo(此StreamReader sr、StreamWriter sw、Action Action、FileProcessOptions fpo=null)
{
如果(fpo==null)
{
fpo=新文件处理选项();
}
列表缓冲区=新列表(fpo.BuferSize);
而(!sr.EndOfStream)
{
buffer.Clear();
而(!sr.EndOfStream&&buffer.Countaction(sw,line));
}
其他的
{
ForEach(line=>action(sw,line));
}
}
}
我处理大量数据,并希望并行处理。
通常数据是存档的,因此使用多个线程来处理数据流是非常重要的

如果您不传递
StreamReader
,而只传递文件名,则可以编写:

Parallel.Foreach(File.ReadLines(filename), (line) => action(sw, line));
如果您传递一个
StreamReader
,您仍然可以执行此操作。您只需要创建一个枚举器来读取它。类似于这里所做的事情:。用这个,你可以写:

LineReaderEnumerable myEnumerable = new LineEnumerator(sr);
Parallel.Foreach(myEnumerable, (line) => action(sw, line));
但是,您可能会遇到一个潜在的问题,因为您可能会有多个线程向该流编写器写入数据。而且
StreamWriter
不支持并发写入。它将抛出一个异常。如果您正在同步对输出文件的访问(例如,使用锁),那么您在这里就可以了

您将遇到的另一个问题是输出的顺序。几乎可以肯定的是,如果您按照
[1,2,3,4,…n]
的顺序读取行,输出顺序将不同。您可能会得到
[1,2,4,3,6,5,7,9,8…n,n-1]
。如果输出顺序很重要,您必须想出一种方法来确保以正确的顺序输出

关于锁,您有:

sr.ProcessParalel(line => 
{ 
    string[] ls = line.Split('\t');
    lock (sw)
    {
        sw.Write(float.Parse(ls[0]));
        sw.Write(int.Parse(ls[1]) * 10 + 1);
        for (int i = 2; i < ls.Length; i++)
        {
            sw.Write(int.Parse(ls[1]));
        }
    }
 });
您可以使用。

最终解决方案执行大致相同的操作:

        public static IEnumerable<string> GetEnumirator(this StreamReader sr)
    {
        while (!sr.EndOfStream)
        {
            yield return sr.ReadLine();
        }
    }

    public static void ProcessParalel(this StreamReader sr, Action<string> action)
    {
        sr.GetEnumirator().AsParallel().ForAll(action);
    }

    public static void ProcessTo(this StreamReader sr, BinaryWriter bw, Action<BinaryWriter, string> action, FileProcessOptions fpo = null)
    {
        sr.ProcessParalel(line =>
        {
            using (MemoryStream ms = new MemoryStream())
            {
                BinaryWriter lbw = new BinaryWriter(ms);

                action(lbw, line);
                ms.Seek(0, SeekOrigin.Begin);

                lock (bw)
                {
                    ms.WriteTo(bw.BaseStream);
                }
            }
        });
    }
公共静态IEnumerable GetEnumirator(此StreamReader sr)
{
而(!sr.EndOfStream)
{
收益返回sr.ReadLine();
}
}
公共静态void ProcessParalel(此StreamReader sr,动作)
{
高级GetEnumirator().AsParallel().ForAll(操作);
}
公共静态void ProcessTo(此StreamReader sr、BinaryWriter bw、Action Action、FileProcessOptions fpo=null)
{
高级进程并行(行=>
{
使用(MemoryStream ms=new MemoryStream())
{
BinaryWriter lbw=新的BinaryWriter(毫秒);
动作(lbw,线路);
Seek女士(0,SeekOrigin.Begin);
锁(bw)
{
ms.WriteTo(bw.BaseStream);
}
}
});
}

在压缩输入流的情况下,我得到了3倍的加速度

先生,您很可能会失望;通常,磁盘操作占用的时间占总时间的90%,而多线程处理对您没有帮助。你试过分析你的代码吗?探查器告诉了你什么?超过50%的CPU用于存档,我想在单独的线程中完成这项工作。你的操作只是写入其他文件吗?不,在数据处理方面几乎没有工作,只需要50%的CPU时间。请查看如何通知其他评论者你的答复。顺序不重要,但同步锁确实会变慢down@user2577265:是什么让你说同步锁减慢了速度?小例子:sr.ProcessParalel(line=>{string[]ls=line.Split('\t');lock(sw){sw.Write(float.Parse(ls[0]);sw.Write(int.Parse(ls[1])*10+1);for(int i=2;iBinaryWriter连接到a,输出到该文件,然后锁定该文件并将内存流的缓冲区复制到输出文件。除非您的个人记录是巨大的,否则您总是可以在锁之外的内存中构建它们,然后非常快速地获取锁并写入文件。关键是.NET文件I/O对象通常不允许多个并发操作,因此您必须同步访问。您实际上不需要自己的
LineEnumerator
的任何精细实现。在
YieldLines()方法中使用
yield return
        public static IEnumerable<string> GetEnumirator(this StreamReader sr)
    {
        while (!sr.EndOfStream)
        {
            yield return sr.ReadLine();
        }
    }

    public static void ProcessParalel(this StreamReader sr, Action<string> action)
    {
        sr.GetEnumirator().AsParallel().ForAll(action);
    }

    public static void ProcessTo(this StreamReader sr, BinaryWriter bw, Action<BinaryWriter, string> action, FileProcessOptions fpo = null)
    {
        sr.ProcessParalel(line =>
        {
            using (MemoryStream ms = new MemoryStream())
            {
                BinaryWriter lbw = new BinaryWriter(ms);

                action(lbw, line);
                ms.Seek(0, SeekOrigin.Begin);

                lock (bw)
                {
                    ms.WriteTo(bw.BaseStream);
                }
            }
        });
    }