长期运行的任务与线程 - 性能

时间:2017-05-23 02:34:10

标签: c# multithreading performance async-await task

假设我有一些长时间运行的后台工作。每个工作都会做一些工作,然后抓住下一个工作并运行它,并一直持续到时间结束。

目前使用“任务”实现。我有一个JobStream,它在循环中一次运行一个作业。我可以同时运行5,15或50个这些流,具体取决于负载。

JobManager

public Task Run(CancellationToken cancellationToken) {
    var jobTasks = Enumerable
        .Range(0, _config.BackgroundProcessor.MaximumSimultaneousJobs)
        .Select(o => JobStream.StartNew(..., () => RunNextJob(cancellationToken), cancellationToken));

    return Task.WhenAll(jobTasks);
}

作业流

public static Task StartNew(Func<Task> nextJobRunner, CancellationToken cancellationToken) {
    var jobStream = new JobStream(nextJobRunner, cancellationToken);

    return jobStream.Start();
}

private Task Start() {
    return Task.Run(async () => {
        do {
            await _nextJobRunner();
        } while (!_cancellationToken.IsCancellationRequested);
    });
}

我的问题是,这里的任务是一个很好的举动,还是我应该用老式的方式创建线程?我最关心的是性能,并确保工作可以独立运行而不会被束缚,因为另一个人正在努力工作。

2 个答案:

答案 0 :(得分:6)

你真的应该使用微软的Reactive Framework(NuGet“System.Reactive”)。它更强大,更简单。

以下是一个例子:

void Main()
{
    int number_of_streams = 10;

    IObservable<int> query =
        Observable
            .Range(0, number_of_streams)
            .Select(stream_number =>
                Observable
                    .Defer(() => Observable.Start(() => nextJob(stream_number)))
                    .Repeat())
            .Merge();

    IDisposable subscription =
        query
            .Subscribe(x => Console.WriteLine(x));
}

public int nextJob(int streamNumber)
{
    Thread.Sleep(10000);
    return streamNumber;
}

这会同时运行10个流,并在每个流中调用int nextJob(int streamNumber)。我为每个作业模拟了10秒的工作,但输出每秒产生一次结果。

此查询会在10个流上永久重复,直到您拨打subscription.Dispose()并且它们全部停止。

答案 1 :(得分:3)

@Enigmativity提供的答案很好。

但是关于作业和线程之间的性能差异:

如果作业长时间运行且CPU密集型,则性能差异可以忽略不计。

如果作业长时间运行但不占用CPU,请使用任务,因为它很方便,节省了创建线程的成本。

如果作业很短,请使用您自己的队列和旧式多线程,因为TPL开销对于短期作业很重要。

与旧式多线程相比,任务是运行后台作业的便捷方式。它确实节省了创建线程的成本,但这个成本仅在您需要创建大量(数千个)线程时才有意义。任务确实为排队和调度以及跟踪结果和异常增加了一些开销,但这仅在您创建大量(数十万)时才有意义。如果工作真正长期运行,情况就不会如此。如果您需要处理这么多长时间运行的作业,那么您需要担心的是比较任务和线程之间的性能差异。