更新控制台应用程序中的多行



我一直在努力与Parallel.For和局部变量。我试图更新百分比在控制台应用程序从并行的。我在多个文档中添加了页面,我想更新每个文档的百分比。

这是我到目前为止的尝试:

我用Console.CursorTop取行号,我想把它传递给一个方法,这个方法会覆盖这行。

Program.cs

中的循环
Parallel.For(0, generationFile.nbOfFile, optionsParallel,
i =>
{                    
string fileName = $"{tmpDirectoryPath}/{i + 1}_{guid}.pdf";
AddPage(fileName, generationFile, i);
});

AddPage方法

private static void AddPage(string fileName, GenerationFile generationFile, int i)
{
var cursorPosition = Console.CursorTop;
//Ajout des pages
for (int j = 0; j < generationFile.SizeMaxFile; j++)
{
Page page = Page.Create(outDoc, size);
AddText(outDoc, page, font, 14, i, fileName, j, generationFile.SizeMaxFile);
for (int k = 0; k < 292; k++)
{
AddImage(outDoc, page, 30, 30);
}
outDoc.Pages.Add(page);
ConsoleManager.UpdateConsole(i, j, cursorPosition, generationFile);
}
}  

UpdateConsole

public static void UpdateConsole(int fileNumber, double progression, int cursorPosition, GenerationFile generationFile)
{
progression = (progression / 100) * generationFile.ArchiveESC; 
Console.ForegroundColor = ConsoleColor.White;
Console.SetCursorPosition(0, cursorPosition);
Console.WriteLine($"rFichier n°{fileNumber + 1}/{generationFile.SizeMaxFile} en cours de création : {progression}%       ", Console.ForegroundColor);
}

我认为一切都很好,除了cursorPosition谁在开始时取一个值,永远不会改变,所以同一行被更新。我知道有一些事情与本地和/或共享变量有关,但我在并行处理方面相当新,所以即使与这个主题和MSDN上的其他线程,我也不明白该怎么做。

我更喜欢的处理进度报告的方式是让所有工作线程报告到一个共享的进度字段,并有一个单独的计时器读取这些字段并向用户报告进度。这让我可以控制汇报进度的频率,而不管项目的处理速度有多快。我还想要一个抽象层,允许以不同的方式报告进度。毕竟,同样的方法可以从控制台、UI中使用,也可以根本不使用。

例如:

public interface IMyProgress
{
void Increment(int incrementValue);
}
public sealed class MyProgress : IMyProgress, IDisposable
{
private readonly int totalItems;
private readonly Timer myTimer;
private volatile int progress;
private int lastUpdatedProgress;
public MyProgress(TimeSpan progressFrequency, int totalItems)
{
this.totalItems = totalItems;
myTimer = new Timer(progressFrequency.TotalMilliseconds);
myTimer.Elapsed += OnElapsed;
myTimer.Start();
}
private void OnElapsed(object sender, ElapsedEventArgs e)
{
var currentProgress = progress;
if (lastUpdatedProgress != currentProgress)
{
lastUpdatedProgress = currentProgress;
var percent = currentProgress * 100 / (double)totalItems;
Console.Write($"rWork progress: {percent}%");
}
}
public void Increment(int incrementValue) => Interlocked.Add(ref progress, incrementValue);
public void Dispose() => myTimer?.Dispose();
}

可以从如下并行方法中调用:

static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var myWorkItems = Enumerable.Range(1, 10000).ToList();
using var progress = new MyProgress(TimeSpan.FromSeconds(1), myWorkItems.Count);
DoProcessing(myWorkItems, progress);
}
private static void DoProcessing(IEnumerable<int> items, IMyProgress progress)
{
Parallel.ForEach(items, item =>
{
Thread.Sleep(20);
progress.Increment(1);
});
}

我在使用回车符时要小心一点。根据我的经验,控制台应用程序往往被其他程序和人类使用,然后很可能输出将被重定向到一个文件,这不支持回车。因此,我会尽量使输出看起来不错。

我会避免尝试移动光标。我已经试过了,但是结果不令人满意,YMMV。

相关内容

最新更新