如何在控制台应用程序 .net 中使用线程有效方式

How to use threading effective way in a console application .net

我有一个 8 核心系统,我正在处理包含数百万行的文本文件,比如 23 个文件包含大量行,需要 2 到 3 个小时才能完成 finish.I 我正在考虑使用 TPL 任务处理文本 files.As 现在我正在使用的代码是一个接一个地顺序处理文本文件,所以我想将其拆分为一个线程中的 5 个文本文件,另一个线程中的 5 个文本文件 etc.Is 这是一个好方法或任何其他方式?我使用的是 .net 4.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());
                        }
                    }

如何将文本文件分成多个批次,每个批次应该 运行 在线程中而不是一个 one.Suppose 如果 23 个文件然后 7 个在一个线程中 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() 等异步方法来访问磁盘上的文件,并协同让 OS 知道它可以切换到新线程对于磁盘 IO 并让线程退出,直到磁盘 IO 操作完成。虽然在此级别进行异步调用很有用,但它本身不会对应用程序的整体性能产生重大影响,因为您的应用程序仍在等待磁盘操作完成,同时什么也不做! (这些调用在从 UI 线程调用时会对软件的响应能力产生很大影响) 因此,我建议在两个单独的线程上将您的软件逻辑拆分为至少两个单独的部分 运行;一个从文件中读取数据,一个处理读取的数据。您可以使用 provider/consumer 模式来帮助这些线程进行交互。 .net 提供的一种很棒的数据结构是 System.Collections.Concurrent.ConcurrentQueue,它在实现多线程 provider/consumer 模式时特别有用。

所以你可以很容易地做这样的事情:

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();

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

全部,真正的瓶颈是当我进行批量插入时,我正在检查插入数据是否存在于数据库中或者什么,我有一个状态列,如果数据存在,它将是 'Y' 或 'N' 通过执行更新 statement.So 更新语句拥塞与插入是 culprit.After 在数据库中进行索引结果从 4 小时减少到 10 分钟,影响很大,但是它赢了:)