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# 如何在控制台应用程序.net中有效地使用线程_C#_Multithreading_.net 4.0_Task Parallel Library - Fatal编程技术网

C# 如何在控制台应用程序.net中有效地使用线程

C# 如何在控制台应用程序.net中有效地使用线程,c#,multithreading,.net-4.0,task-parallel-library,C#,Multithreading,.net 4.0,Task Parallel Library,我有8个核心系统,我正在处理大量文本文件,其中包含数百万行,比如23个文件包含大量行,需要2到3个小时才能完成。我正在考虑使用TPL任务来处理文本文件。到目前为止,我正在使用的代码是按顺序逐个处理文本文件,所以我正在考虑像这样拆分它一个线程中有5个文本文件,另一个线程中有5个文本文件,等等。这是一个好方法还是其他方法?我使用的是.NET4.0,我使用的代码如下所示 foreach (DataRow dtr in ds.Tables["test"].Rows) {

我有8个核心系统,我正在处理大量文本文件,其中包含数百万行,比如23个文件包含大量行,需要2到3个小时才能完成。我正在考虑使用TPL任务来处理文本文件。到目前为止,我正在使用的代码是按顺序逐个处理文本文件,所以我正在考虑像这样拆分它一个线程中有5个文本文件,另一个线程中有5个文本文件,等等。这是一个好方法还是其他方法?我使用的是.NET4.0,我使用的代码如下所示

foreach (DataRow dtr in ds.Tables["test"].Rows)
                {
                    string filename = dtr["ID"].ToString() + "_cfg";
                    try
                    {
                        foreach (var file in
                          Directory.EnumerateFiles(Path.GetDirectoryName(dtr["FILE_PATH"].ToString()), "*.txt"))
                        {
                            id = file.Split('\\').Last();
                            if (!id.Contains("GMML"))
                            {
                                strbsc = id.Split('_');
                                id = strbsc[0];
                            }
                            else
                            {
                                strbsc = file.Split('-');
                                id = ("RC" + strbsc[1]).Replace("SC", "");
                            }
                            ProcessFile(file, id, dtr["CODE"].ToString(), dtr["DOR_CODE"].ToString(), dtr["FILE_ID"].ToString());
                        }
                    }
如何将文本文件分为多个批,每个批应该在线程中运行,而不是一个一个地运行。假设如果23个文件,那么一个线程中7个文件,一个线程中7个文件,另一个线程中2个文件。还有一件事是,我正在将所有这些数据从文本文件移动到oracle数据库

编辑

如果我像这样使用它,那么它是值得的,但是如何将文件分批处理呢

Task.Factory.StartNew(() => {ProcessFile(file, id, dtr["CODE"].ToString(), dtr["DOR_CODE"].ToString(), dtr["FILE_ID"].ToString()); });

将文件分成多个块似乎不是一个好主意,因为它的性能提升与文件在磁盘上的放置方式有关。但由于磁盘IO操作的异步性质,我强烈建议异步访问该文件。有几种方法可以做到这一点,您总是可以选择这些方法的组合。 在最低级别,您可以使用异步方法,如StreamWriter.WriteAsync()或StreamReader.ReadAsync()来访问磁盘上的文件,并协同让操作系统知道它可以切换到磁盘IO的新线程,并释放线程,直到磁盘IO操作完成。虽然在这个级别进行异步调用很有用,但它本身并不会对应用程序的整体性能产生重大影响,因为应用程序仍在等待磁盘操作完成,而在此期间什么也不做!(当从UI线程调用这些调用时,它们会对软件的响应性产生很大影响) 因此,我建议将软件逻辑拆分为至少两个独立的部分,在两个独立的线程上运行;一个用于从文件中读取数据,另一个用于处理读取的数据。您可以使用提供者/使用者模式来帮助这些线程进行交互。 net提供的一个很好的数据结构是System.Collections.Concurrent.ConcurrentQueue,它在实现多线程提供者/使用者模式时特别有用

因此,您可以轻松地执行以下操作:

System.Collections.Concurrent.ConcurrentQueue<string> queue = new System.Collections.Concurrent.ConcurrentQueue<string>();
bool readFinished = false;  
Task tRead = Task.Run(async () => 
{
    using (FileStream fs = new FileStream())
    {
        using (StreamReader re = new StreamReader(fs))
        {
            string line = "";
            while (!re.EndOfStream)
                queue.Enqueue(await re.ReadLineAsync());
        }
    }
});

Task tLogic = Task.Run(async () =>
{
    string data ="";
    while (!readFinished)
    {
        if (queue.TryDequeue(out data))
            //Process data
        else
            await Task.Delay(100);
    }
});

tRead.Wait();
readFinished = true;
tLogic.Wait();
System.Collections.Concurrent.ConcurrentQueue=new System.Collections.ConcurrentQueue();
bool readFinished=false;
Task-tRead=Task.Run(异步()=>
{
使用(FileStream fs=new FileStream())
{
使用(StreamReader re=新StreamReader(fs))
{
字符串行=”;
而(!re.EndOfStream)
排队(等待re.ReadLineAsync());
}
}
});
Task tLogic=Task.Run(异步()=>
{
字符串数据=”;
而(!readFinished)
{
if(queue.TryDequeue(out数据))
//过程数据
其他的
等待任务。延迟(100);
}
});
等一下;
readFinished=true;
tLogic.Wait();

这个简单的示例使用StreamReader.ReadLineAsync()从文件中读取数据,而一个好的做法是将固定长度的字符读入char[]缓冲区,然后将该数据添加到队列中。您可以在一些测试之后找到优化的缓冲区长度。

将文件拆分为多个块似乎不是一个好主意,因为它的性能提升与文件在磁盘上的放置方式有关。但由于磁盘IO操作的异步性质,我强烈建议异步访问该文件。有几种方法可以做到这一点,您总是可以选择这些方法的组合。 在最低级别,您可以使用异步方法,如StreamWriter.WriteAsync()或StreamReader.ReadAsync()来访问磁盘上的文件,并协同让操作系统知道它可以切换到磁盘IO的新线程,并释放线程,直到磁盘IO操作完成。虽然在这个级别进行异步调用很有用,但它本身并不会对应用程序的整体性能产生重大影响,因为应用程序仍在等待磁盘操作完成,而在此期间什么也不做!(当从UI线程调用这些调用时,它们会对软件的响应性产生很大影响) 因此,我建议将软件逻辑拆分为至少两个独立的部分,在两个独立的线程上运行;一个用于从文件中读取数据,另一个用于处理读取的数据。您可以使用提供者/使用者模式来帮助这些线程进行交互。 net提供的一个很好的数据结构是System.Collections.Concurrent.ConcurrentQueue,它在实现多线程提供者/使用者模式时特别有用

因此,您可以轻松地执行以下操作:

System.Collections.Concurrent.ConcurrentQueue<string> queue = new System.Collections.Concurrent.ConcurrentQueue<string>();
bool readFinished = false;  
Task tRead = Task.Run(async () => 
{
    using (FileStream fs = new FileStream())
    {
        using (StreamReader re = new StreamReader(fs))
        {
            string line = "";
            while (!re.EndOfStream)
                queue.Enqueue(await re.ReadLineAsync());
        }
    }
});

Task tLogic = Task.Run(async () =>
{
    string data ="";
    while (!readFinished)
    {
        if (queue.TryDequeue(out data))
            //Process data
        else
            await Task.Delay(100);
    }
});

tRead.Wait();
readFinished = true;
tLogic.Wait();
System.Collections.Concurrent.ConcurrentQueue=new System.Collections.ConcurrentQueue();
bool readFinished=false;
Task-tRead=Task.Run(异步()=>
{
使用(FileStream fs=new FileStream())
{
使用(StreamReader re=新StreamReader(fs))
{
字符串行=”;
而(!re.EndOfStream)
排队(等待re.ReadLineAsync());
}
}
});
Task tLogic=Task.Run(异步()=>
{
字符串数据=”;
而(!readFinished)
{
if(queue.TryDequeue(out数据))
//过程数据
其他的
等待任务。延迟(100);
}
});
等一下;
readFinished=true;
tLogic.Wait();

这个简单的示例使用StreamReader.ReadLineAsync()从文件中读取数据,而一个好的做法是将固定长度的字符读入char[]缓冲区,然后将该数据添加到队列中。您可以在一些测试之后找到优化的缓冲区长度。

总之,真正的瓶颈是当我进行大规模插入时,我正在检查插入数据是否存在于数据库中,或者什么,我有一个状态列,其中