【发布时间】:2019-02-16 00:33:32
【问题描述】:
我有一个控制台应用程序,它使用类库来执行一些长时间运行的任务。这是一个 .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、Job2、Job3 实现 IJob)
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();
}
此设置运行良好,我可以通过创建ShellProgressBar 实例并使用我必须更新的IProgress 实例来显示我的HostedService 的进度条。
但是,我还需要运行 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) 并将它们显示为让我们说'并行作业'的子进度条。
这是我正在寻求一些帮助以了解如何实现这一点的地方。
注意:我不想在包含 MyService 的类库中依赖 ShellProgressBar
非常感谢任何帮助。
【问题讨论】:
-
在任务列表上使用 Parallel.ForEach 有什么意义?任务已经在后台运行,因此是并行的。因此,您所做的就是在 Parallel 中浪费昂贵的线程,只是为了使用 Task.Run 启动另一个线程。您不应该混合使用 Parallel.ForEach 和任务,因为它们都使用宝贵的线程资源。如果您希望代码并行运行并具有高度可扩展性,请使用 Parallel,如果您希望异步运行代码(也可以并行运行),请使用 Task。
-
我明白为什么会出现这种混乱。在此示例中,我将其命名为 Task,但它不是 C# 任务。我已经更新了示例代码以更好地表达这一点。
-
这些
"IJob" 派生的工作是否有能力报告他们的进度? -
您好,感谢您的评论。我用详细的示例代码重写了我的问题。
-
或者,您可以尝试使用 Hangire。这是在 .NET 和 .NET Core 应用程序中执行后台处理的简单方法。无需 Windows 服务或单独的进程。它也是开源的。
标签: c# .net asp.net-core .net-core