基于 TPL 的循环服务:右工作者方法签名,异步

TPL-based looping service: right worker method signature, asynchrony

关于正确的工作方法签名,我需要了解以下内容:

备注

尽管有 cpu 绑定代码,但可以选择调用异步版本的 io 绑定方法(sql 查询)。所以它可能是全部同步或部分异步。至于Worker方法中代码的性质。


public class LoopingService
{
    private CancellationTokenSource cts;
    // ..

    void Worker(CancellationToken cancellationToken)
    {
        while(!cancellationToken.IsCancellationRequested)
        {
            // mixed, CPU/IO-bound code

            try {
                // sql query (can be called either as sync/async)
                var lastId = documentService.GetLastDocument().Id;

                // get next document from a public resource (third-party code, sync)
                // can be moved to a web api
                var document = thirdPartyDocumentService.GetNextDocument(lastId);

                // apply different processors in parallel
                var tasksList = new List<Task>();

                foreach(var processor in documentService.Processors) {
                    // each processor checks if it's applicable
                    // which may include xml-parsing, additional db calls, regexes
                    // if it's applicable then document data is inserted into the db
                    var task = new Task(() => processor.Process(document));
                    tasksList.Add(task);
                    task.Start();
                }

                // or 
                // var tasksList = documentService.ProcessParallel(document);

                Task.WaitAll(tasksList.ToArray(), cancellationToken);
            }
            catch(Exception ex) {
                logger.log(ex);
            }
        }  
    }

    public void Start()
    {
        this.cts = new CancellationTokenSource();
        Task.Run(() => this.Worker(cts.Token));
    }

    public void Stop()
    {
        this.cts.Cancel();
        this.cts.Dispose();
    }

}

is there a point in returning Task instead of void for Worker method?

如果 Worker 是一个真正的异步方法,它应该 return 一个 Task 以便您能够等待它。如果它只是一个在后台线程上运行的同步方法,则没有必要将 return 类型从 void 更改为该方法不应该 return 任何东西。

what should be the return value of Worker method when marked as returning Task object?

没有。如果该方法是异步的并且标记为 async 且 return 类型为 Task,则它不应 return 任何值:

async Task Worker(CancellationToken cancellationToken) { ... }

请注意,除非您实际在其中使用 await 关键字,否则将方法定义为 async 是没有意义的。

what signature and body of Worker method should be given the work it completes is long-running CPU/IO-bound work? Should I follow this recommendation?

是的,可能吧。如果您出于某种原因在同一方法中同时执行异步和同步(CPU 绑定)工作,您应该更喜欢使用异步签名,但不要将同步内容包装在 Task.Run 中。那么您的服务将如下所示:

public class LoopingService
{
    private CancellationTokenSource cts;

    async Task Worker(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            await ...
        }
    }

    public async Task Start()
    {
        this.cts = new CancellationTokenSource();
        await this.Worker(cts.Token).ConfigureAwait(false);
    }

    public void Stop()
    {
        this.cts.Cancel();
        this.cts.Dispose();
    }

}

理想情况下,您的方法应该是异步的或 CPU 绑定的,但不能同时是两者。