【问题标题】:Stop waiting (Task.Delay(-1)) after event was invoked [duplicate]调用事件后停止等待(Task.Delay(-1))[重复]
【发布时间】:2020-12-20 23:52:53
【问题描述】:

我有这样的代码

public async Task DoStuff()
{
    _client.Ready += () => client_Ready("test");

    await Task.Delay(-1);
}

private async Task client_Ready(string message)
{
    await _client.SendMessageAsync(message);
}

我怎么能说在client_Ready 被调用一次之后整个DoStuff 必须结束/执行返回而不是等待?

有没有一种“不错”的方法,或者我必须做一些工作,比如抛出异常并在“上方”捕获它?

MRE:

using System;
using System.Threading.Tasks;

public class Program
{
    public static async Task RandomlyDelayedStuff()
    {
        Console.WriteLine("this ended");
        await Task.Delay(200);
    }

    public static async Task DoStuff()
    {
        var rnd = new Random();

        await Task.Delay(rnd.Next(0, 5000)).ContinueWith(async task =>
        {
            await RandomlyDelayedStuff();
        });

        await Task.Delay(-1);
    }
    public static async Task Main()
    {
        await DoStuff();
        Console.WriteLine("ended");
    }
}

【问题讨论】:

  • 我不明白你的await Task.Delay(-1); 应该达到什么目的。如果您只是删除它会发生什么?
  • 我不明白这个问题。你是说“我不希望DoStuff 在client_Ready 完成执行之前返回”?如果是这样 - 为什么你想要这个?
  • @mjwills 我正在连接到client,一段时间后X 返回答案并调用Ready(client_Ready 方法)。我使用了Task.Delay(-1),所以程序不会立即退出DoStuff 函数(在我收到Ready 之前)。问题是,即使在事件被调用后它也永远不会离开它
  • 是的,请提供 MRE,因为这部分需要“不退出 DoStuff”对我来说没有意义。您分配了一个事件处理程序,您只需要调用该处理程序,我不明白为什么DoStuff 立即结束是一个问题。

标签: c# async-await task


【解决方案1】:

使用取消令牌。将令牌传递给延迟调用。您可以创建一个 CancellationTokenSource 并对其调用取消,这将启动对令牌的取消调用。

CancellationTokenSource cancelTokenSource = new CancellationTokenSource();

public async Task DoStuff()
{
    _client.Ready += () => client_Ready("test");

    await Task.Delay(-1, cancelTokenSource.Token);

    // do something else here if desired
}

private async Task client_Ready(string message)
{
    await _client.SendMessageAsync(message);
    cancelTokenSource.Cancel();
}

【讨论】:

    【解决方案2】:

    您应该能够通过取消令牌来完成此操作。

    代码未经测试,我已延迟完成,并使用取消来重置,但从未使用无限计时器和取消。

    const int cDelayMS = -1;
    private System.Threading.CancellationTokenSource mCancel = new();
    
    DoStuff()
    {
        Task.Delay(cDelayMS, mCancel.Token).ContinueWith(
                    async antecedent =>
                    {
                        if (antecedent.Status == TaskStatus.Canceled)
                        {
                            // do whatever here
                        }
                    });
    }
    

    【讨论】:

      猜你喜欢
      • 2016-09-03
      • 2015-01-04
      • 2013-10-30
      • 1970-01-01
      • 1970-01-01
      • 2014-08-12
      • 2020-06-30
      • 2019-08-26
      • 1970-01-01
      相关资源
      最近更新 更多