首页 > 解决方案 > .net core - 传递未知数量的 IProgress到类库

问题描述

我有一个控制台应用程序,它使用类库来执行一些长时间运行的任务。这是一个 .net core 控制台应用程序,使用 .net core Generic Host。我还使用ShellProgressBar库来显示一些进度条。

我的托管服务看起来像这样

internal class MyHostedService : IHostedService, IDisposable
{
    private readonly ILogger _logger;
    private readonly IMyService _myService;
    private readonly IProgress<MyCustomProgress> _progress;
    private readonly IApplicationLifetime _appLifetime;
    private readonly ProgressBar _progressBar;
    private readonly IProgressBarFactory _progressBarFactory;

    public MyHostedService(
        ILogger<MyHostedService> logger, 
        IMyService myService,
        IProgressBarFactory progressBarFactory,
        IApplicationLifetime appLifetime)
    {
        _logger = logger;
        _myService = myService;
        _appLifetime = appLifetime;
        _progressBarFactory = progressBarFactory;

        _progressBar = _progressBarFactory.GetProgressBar();        // this just returns an instance of ShellProgressBar

        _progress = new Progress<MyCustomProgress>(progress =>
        {
            _progressBar.Tick(progress.Current);
        });
    }

    public void Dispose()
    {
        _progressBar.Dispose();
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _myService.RunJobs(_progress);
        _appLifetime.StopApplication();

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}

哪里MyCustomProgress看起来像这样

public class MyCustomProgress
{
    public int Current {get; set;}
    public int Total {get; set;}
}

MyService看起来像这样( , Job1, implement Job2)Job3IJob

public class MyService : IMyService
{
    private void List<IJob> _jobsToRun;

    public MyService()
    {
        _jobsToRun.Add(new Job1());
        _jobsToRun.Add(new Job2());
        _jobsToRun.Add(new Job3());
    }

    public void RunJobs(IProgress<MyCustomProgress> progress)
    {           
        _jobsToRun.ForEach(job => 
        {
            job.Execute();

            progress.Report(new MyCustomProgress { Current = _jobsToRun.IndexOf(job) + 1, Total = _jobsToRun.Count() });
        });
    }

}

并且IJob

public interface IJob
{
    void Execute();
}

此设置运行良好,我可以HostedService通过创建一个ShellProgressBar实例并使用IProgress我必须更新它的一个实例来显示我的进度条。

但是,我还有另一个实现IMyService,我也需要运行它,看起来像这样

public class MyService2 : IMyService
{
    private void List<IJob> _sequentialJobsToRun;
    private void List<IJob> _parallelJobsToRun;

    public MyService()
    {
        _sequentialJobsToRun.Add(new Job1());
        _sequentialJobsToRun.Add(new Job2());
        _sequentialJobsToRun.Add(new Job3());


        _parallelJobsToRun.Add(new Job4());
        _parallelJobsToRun.Add(new Job5());
        _parallelJobsToRun.Add(new Job6());
    }

    public void RunJobs(IProgress<MyCustomProgress> progress)
    {       
        _sequentialJobsToRun.ForEach(job => 
        {
            job.Execute();

            progress.Report(new MyCustomProgress { Current = _jobsToRun.IndexOf(job) + 1, Total = _jobsToRun.Count() });
        });

        Parallel.ForEach(_parallelJobsToRun, job => 
        {
            job.Execute();

            // Report progress here
        });
    }

}

这是我正在努力解决的问题。当_parallelJobsToRun执行时,我需要能够创建一个新的子ShellProgressBar( ShellProgressBar.Spawn) 并将它们显示为让我们说“并行作业”的子进度条。

这就是我正在寻找一些关于如何实现这一目标的帮助的地方。

注意:我不想ShellProgressBar在我的类库中依赖MyService

非常感谢任何帮助。

标签: c#.netasp.net-core.net-core

解决方案


根据我对您的问题的理解,问题是您如何显示同步作业和并行作业的完成进度。

理论上,并行作业可以同时开始和结束,因此您可以将并行作业视为单个作业。不要使用连续作业的计数作为总数,而是将该数字增加一。这对于少量并行作业可能是令人满意的。

如果要在并行作业之间添加进度,则需要在代码中处理多线程,因为并行作业将同时运行

object pJobLock = new object();
int numProcessed = 0;
foreach(var parallelJob in parallelJobs)
{
    parallelJob.DoWork();
    lock (pJobLock)
    {
        numProcessed++;
        progress.Report(new MyCustomProgress { Current = numProcessed, Total = parallelJobs.Count() });
    }
}

推荐阅读