首页 > 解决方案 > C# 异步任务在完成之前完成

问题描述

我正在开发一个网络应用程序,它从 websocket 接收数据,对其进行修改,并将其上传到数据服务。上传数据需要一些时间,我想隐藏这种延迟,一次上传多条消息。上传完成后,我需要通过 websocket 发回确认。

我创建了一个工作队列来保存所有未完成的任务。这似乎运作良好,所以我没有包括它。但是我的上传任务似乎在它实际完成之前就完成了。这是一个精简的样本。

private async Task UploadDataAsync(string data, CancellationToken cancellationToken)
{
    Task uploadTask = new Task(async () =>
    {
        // Simulates uploading data
        await Task.Delay(5000, cancellationToken);
    });

    _ = uploadTask.ContinueWith(async (t1) =>
    {
        // Clean up the task
        await RemoveTask(t1);

        if (t1.IsCompletedSuccessfully)
            await SendAck(this, data, cancellationToken);
        else if (t1.IsFaulted)
            logger.LogError(t1.Exception, $"An error occurred while uploading {data}");
        else if (t1.IsCanceled)
            logger.LogWarning($"An upload task {data} was canceled");

    }, TaskScheduler.Default);

    await AddTask(uploadTask);
    uploadTask.Start();
}

在前面的代码中,确认是在数据上传之前发送的。令人惊讶的是,这似乎是因为我的 Task 使用了异步 lambda。由于我不明白的原因uploadTask,等待上传时完成。所以我把它改成这样:

private async Task UploadDataAsync(string data, CancellationToken cancellationToken)
{
    Task uploadTask = new Task(() =>
    {
        // Simulates uploading data
        Task.Delay(5000, cancellationToken).Wait();
    });

    _ = uploadTask.ContinueWith((t1) =>
    {
        // Clean up the task
        RemoveTask(t1).Wait();

        if (t1.IsCompletedSuccessfully)
            SendAck(this, data, cancellationToken).Wait();
        else if (t1.IsFaulted)
            logger.LogError(t1.Exception, $"An error occurred while uploading {data}");
        else if (t1.IsCanceled)
            logger.LogWarning($"An upload task {data} was canceled");

    }, TaskScheduler.Default);

    await AddTask(uploadTask);
    uploadTask.Start();
}

现在一切都以正确的顺序执行,除非出现问题或操作被取消(例如服务器关闭)。现在我正在处理 AggregateExceptions 和 TaskCanceledExceptions。

这似乎应该比我做的更容易。我做错了吗?

编辑UploadDataAsync添加需要上下文的伪代码。

protected override async Task DoConnection(CancellationToken cancellationToken)
{
    while (_websocket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested)
    {
        // Simulates getting websocket data
        string result = await _websocket.ReceiveAsync();

        // This should only asynchronously wait for the upload task to get
        // created. It should not wait for the upload to complete.
        await OnDataReceived(result, cancellationToken);
    }
}

标签: c#async-await

解决方案


现在,您打电话uploadTask.Start()并继续,无需等待它完成。(甚至在你打电话之前AddTask发生)。您应该等待,而不是仅仅启动它并立即继续。uploadTask.Start()uploadTask


推荐阅读