Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.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#_.net_Multithreading_Console - Fatal编程技术网

C# 从多个线程更新控制台文本不工作

C# 从多个线程更新控制台文本不工作,c#,.net,multithreading,console,C#,.net,Multithreading,Console,我正在控制台应用程序中以多线程模式执行/处理非常大的文件 当我不从线程更新/写入控制台时,测试整个过程大约需要1分钟 但是,当我尝试从线程更新/写入控制台以显示进度时,进程卡住了,它永远不会完成,需要等待几分钟甚至几个小时。而且控制台文本/窗口也没有按应有的方式更新 更新-1:根据少数响应者的请求,我添加了能够重现相同错误/问题的最小代码 以下是线程函数/方法的代码: using System; using System.Collections; using System.Collections

我正在控制台应用程序中以多线程模式执行/处理非常大的文件

当我不从线程更新/写入控制台时,测试整个过程大约需要1分钟

但是,当我尝试从线程更新/写入控制台以显示进度时,进程卡住了,它永远不会完成,需要等待几分钟甚至几个小时。而且控制台文本/窗口也没有按应有的方式更新

更新-1:根据少数响应者的请求,我添加了能够重现相同错误/问题的最小代码

以下是线程函数/方法的代码:

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Large_Text_To_Small_Text
{
class Program
{
    static string sAppPath;
    static ArrayList objThreadList;

    private struct ThreadFileInfo
    {
        public string sBaseDir, sRFile;
        public int iCurFile, iTFile;
        public bool bIncludesExtension;
    }

    static void Main(string[] args)
    {
        string sFileDir;
        DateTime dtStart;


        Console.Clear();
        sAppPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
        sFileDir = @"d:\Test";
        dtStart = DateTime.Now;
        ///process in multi threaded mode
        List<string> lFiles;

        lFiles = new List<string>();
        lFiles.AddRange(Directory.GetFiles(sFileDir, "*.*", SearchOption.AllDirectories));
        if (Directory.Exists(sFileDir + "-Processed") == true)
        {
            Directory.Delete(sFileDir + "-Processed", true);
        }
        Directory.CreateDirectory(sFileDir + "-Processed");
        sPrepareThreading();
        for (int iFLoop = 0; iFLoop < lFiles.Count; iFLoop++)
        {
            //Console.WriteLine(string.Format("{0}/{1}", (iFLoop + 1), lFiles.Count));
            sThreadProcessFile(sFileDir + "-Processed", lFiles[iFLoop], (iFLoop + 1), lFiles.Count, Convert.ToBoolean(args[3]));

        }
        sFinishThreading();

        Console.WriteLine(DateTime.Now.Subtract(dtStart).ToString());
        Console.ReadKey();
        return;
    }

    private static void sProcSO(object oThreadInfo)
    {
        var inputLines = new BlockingCollection<string>();
        long lACounter, lCCounter;
        ThreadFileInfo oProcInfo;

        lACounter = 0;
        lCCounter = 0;
        oProcInfo = (ThreadFileInfo)oThreadInfo;
        var readLines = Task.Factory.StartNew(() =>
        {
            foreach (var line in File.ReadLines(oProcInfo.sRFile))
            {
                inputLines.Add(line);
                lACounter++;
            }
            inputLines.CompleteAdding();
        });

        var processLines = Task.Factory.StartNew(() =>
        {
            Parallel.ForEach(inputLines.GetConsumingEnumerable(), line =>
            {
                lCCounter++;
                /*
                    some process goes here
                */

                /*If i Comment out these lines program get stuck!*/
                //Console.SetCursorPosition(0, oProcInfo.iCurFile);
                //Console.Write(oProcInfo.iCurFile + " = " + lCCounter.ToString());
            });
        });

        Task.WaitAll(readLines, processLines);
    }

    private static void sPrepareThreading()
    {
        objThreadList = new ArrayList();
        for (var iTLoop = 0; iTLoop < 5; iTLoop++)
        {
            objThreadList.Add(null);
        }
    }

    private static void sThreadProcessFile(string sBaseDir, string sRFile, int iCurFile, int iTFile, bool bIncludesExtension)
    {
        Boolean bMatched;
        Thread oCurThread;
        ThreadFileInfo oProcInfo;

    Salma_RecheckThread:
        bMatched = false;
        for (int iTLoop = 0; iTLoop < 5; iTLoop++)
        {
            if (objThreadList[iTLoop] == null || ((System.Threading.Thread)(objThreadList[iTLoop])).IsAlive == false)
            {
                oProcInfo = new ThreadFileInfo()
                {
                    sBaseDir = sBaseDir,
                    sRFile = sRFile,
                    iCurFile = iCurFile,
                    iTFile = iTFile,
                    bIncludesExtension = bIncludesExtension
                };
                oCurThread = new Thread(sProcSO);
                oCurThread.IsBackground = true;
                oCurThread.Start(oProcInfo);
                objThreadList[iTLoop] = oCurThread;
                bMatched = true;
                break;
            }
        }
        if (bMatched == false)
        {
            System.Threading.Thread.Sleep(250);
            goto Salma_RecheckThread;
        }
    }


    private static void sFinishThreading()
    {
        Boolean bRunning;
    Salma_RecheckThread:
        bRunning = false;
        for (int iTLoop = 0; iTLoop < 5; iTLoop++)
        {
            if (objThreadList[iTLoop] != null && ((System.Threading.Thread)(objThreadList[iTLoop])).IsAlive == true)
            {
                bRunning = true;
            }
        }
        if (bRunning == true)
        {
            System.Threading.Thread.Sleep(250);
            goto Salma_RecheckThread;
        }
    }

}
}
Update-1:要进行测试,只需将sFileDir更改为包含一些大文本文件的任何文件夹,或者如果愿意,可以从以下链接下载一些大文本文件:

https://wetransfer.com/downloads/8aecfe05bb44e35582fc338f623ad43b20210602005845/bcdbb5

我是否缺少从线程更新控制台文本的任何函数/方法?

您的冻结问题可能与C或代码无关

在控制台窗口左上角的图标上。。右击 选择属性 删除快速编辑模式和插入模式选项

你可以用谷歌搜索这个特性,但本质上表现在你上面描述的问题上


另一方面,格式化问题似乎确实存在,这里您需要创建一个类来序列化从单个线程到控制台窗口的写入。消费者/生产者模式会起作用,您可以使用BlockingCollection非常轻松地实现这一点

我无法复制它。在我的测试中,这个过程总是运行到完成,而不会被卡住。但输出到处都是,因为下面两行没有同步:

Console.SetCursorPosition(0, oProcInfo.iCurFile);
Console.Write(oProcInfo.iCurFile + " = " + lCCounter.ToString());
计算中涉及的许多线程中的每个线程与其他线程同时调用这两条语句。这使得一个线程可以抢占另一个线程,并在第一个线程有机会在控制台中写入之前移动光标。要解决此问题,必须添加适当的同步,最简单的方法是使用以下语句:

class Program
{
    static object _locker = new object();
在sProcSO方法中:

如果您想了解有关线程同步的更多信息,我建议您使用以下联机资源:


如果您想听听我对问题中代码的看法,并且您不介意接受批评,我的意见是,老实说,代码中充满了问题,最好的做法是扔掉它,从头开始。使用古老的数据结构ArrayList???,自由地使用从对象到特定类型的转换,自由地使用goto语句,在公共类型成员中使用匈牙利符号,所有这些都使代码难以理解,并且容易让bug潜入。我发现特别有问题的是,每个文件都使用专用线程与所有其他文件并行处理,然后每个专用线程使用ThreadPool thread Task.Factory.StartNew以未配置的MaxDegreeOfParallelism启动并行循环parallel.ForEach。此设置确保线程池将严重饱和,线程的可用性将永远无法满足需求。很可能还会导致存储设备的使用效率极低,尤其是当硬件是经典硬盘时。

lCCounter++在ForEach委托中不安全。但这不会导致上面显示的代码无法完成。也就是说,上面没有证据表明代码实际上没有完成。您正在以不确定的顺序异步写入控制台,这可能会在屏幕上造成各种意外的视觉效果。但这并不意味着循环没有完成。请修复您的问题,使其包含一个可靠地再现问题的方法。@PeterDuniho,谢谢您的回答,但您想让我共享整个代码吗?这会让问题变得非常大:你想让我分享整个代码吗不,当然不是。请阅读。然后你就会知道你应该分享什么。如果您仍然不确定,请阅读并密切关注该页面底部链接的文章。我们需要知道ThreadFileInfo是什么,以便能够编译代码并进行实验。ThreadFileInfo要么与问题相关,应该包括在内,要么只是噪音,应该全部删除。一些想法:您的代码没有错误处理。如果readLines任务失败,processLines任务将被卡住,永远等待BlockingCollection的完成,因此task.WaitAllreadLines,processLines;也将永远等待。未指定MaxDegreeOfParallelism时,Parallel.ForEach会使线程池饱和。建议您具体说明。默认情况下,它还使用块分区,您可能应该使用EnumerablePartitionPerOptions.NoBuffering选项禁用块分区。主席先生,锁定的东西以某种方式解决了这个问题,但是如果不使用锁/写来控制进程,看起来会花更长的时间吗?任何 主意还有,我如何隐藏/禁用闪烁的光标,因为光标从这里到那里快速移动,阅读/理解状态变得越来越困难:谢谢你的帮助again@SalmaBegumConsole类是线程安全的,因此每个调用都在内部同步。通过添加额外的同步层,我希望增加一些开销,但这应该是微不足道的。除非你拿着锁也在做其他事情。关于如何改进应用程序的UI,我没有什么具体的建议。也许从控制台应用程序切换到WinForms应用程序?
class Program
{
    static object _locker = new object();
lock (_locker)
{
    Console.SetCursorPosition(0, oProcInfo.iCurFile);
    Console.Write(oProcInfo.iCurFile + " = " + lCCounter.ToString());
}