在 HttpListener、GetContextAsync 之后使用 Task.Run 或 ContinueWith?

Use Task.Run or ContinueWith after HttpListener,GetContextAsync?

以下有什么区别(如果有的话):

_listener = new HttpListener();

// Wait for an incoming request, then start a new task
// that executes ProcessContext()
var httpctx = await _listener.GetContextAsync();
await Task.Run(() => ProcessContext(httpctx));

/* -- or -- */

// Use ContinueWith to pass the incoming request to ProcessContext()
await _listener.GetContextAsync().ContinueWith(async (tsk) => {
    if (tsk.Status != TaskStatus.RanToCompletion) Debug.Assert(false);
    await ProcessContext(tsk.Result);
});

第一种方法需要一个笨拙的闭包来将上下文传递给新任务,仅凭这一点我倾向于认为第二种方法更好。不过我还是异步的新手,所以我可能是错的。

总体目标是让任务不断等待 GetContextAsync 的结果:

async Task Listen()
{
    while (_listener != null && _listener.IsListening)
    {
        // Use one of the methods above to get the context
        // and pass that context to a new task. This allows
        // the current task to loop around and immediately
        // resume listening for incoming requests
    }
}

第一个选项是使用 Task.RunProcessContext 卸载到 ThreadPool 线程。第二个选项不这样做。它只是完成 GetContextAsync 并继续执行 ProcessContext.

然而,由于 ContinueWith 不打算与 async-await 一起使用,它将 运行 同步直到第一个等待,然后两者继续并行并 return 控制到调用方法(所以不要混用 ContinueWith 和 async-await)

不清楚为什么这些是您的选择,因为您可以简单地调用这两种方法并等待结果:

var httpctx = await _listener.GetContextAsync();
await ProcessContext(httpctx);

它与使用 ContinueWith(正确使用时)非常相似,但显然更简单。使用 Task.Run 在这里并不是很有帮助。它主要用于并行代码或从 UI 线程卸载。