【问题标题】:Overlapping execution but only execute expensive task inside once重叠执行但只在内部执行一次昂贵的任务
【发布时间】:2018-03-22 15:33:30
【问题描述】:

我有一个异步方法,有时调用它的速度比它的执行时间快,这会导致重叠并比必要的更频繁地执行昂贵的任务。 我的目标是让所有调用与重叠中的第一个调用重叠,只执行一次昂贵的任务。

public static void MethodA() { Console.Write("A"); }
public static Task MethodB() { Console.Write("B"); return Task.Delay(500); }
public static void MethodC() { Console.Write("C"); }
public static async Task MethodAsync() {
    //TODO: Block any additional calls until first call has finished.
    //      Additional calls then exit immediately afterwards.
    Console.Write("<");
    MethodA();
    await MethodB();
    MethodC();
    Console.Write(">");
}
public static void Main() {
    MethodAsync();
    MethodAsync();
    Console.ReadLine();
}

鉴于上面的示例 MethodAsync 被调用两次,没有延迟,这导致 MethodB 执行两次。 我想让第一个调用正常执行,第二个调用等待(异步)直到第一个调用完成,然后退出而不执行任何操作。

我想出的最好的方法是使用 SemaphoreSlim 和一个整数变量:https://dotnetfiddle.net/7H8SZx

我想知道是否有其他/更好的方法来做到这一点。

编辑:
鉴于上面的示例(不是链接),输出将类似于&lt;AB&lt;ABC&gt;C&gt;。 目标是有类似&lt;AB&lt;C&gt;&gt; 的东西,或者如果我毫不拖延地拨打 10 次电话(这几乎不会发生)&lt;AB&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;C&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;

另一个例子:
MethodAsync 方法无延迟等待 2 次,然后在 2 秒后再次等待 3 次无延迟。 目标是拥有&lt;AB&lt;C&gt;&gt;&lt;AB&lt;&lt;C&gt;&gt;&gt;

【问题讨论】:

  • 你为什么不等MethodAsync()
  • 我只包含 Main 方法来制作一个工作示例。实际的项目在不同的地方有调用。
  • 您没有正确执行此操作,问题不在于等待异步调用。因为您没有使用await,所以下一个方法开始执行,而第一个方法仍在运行。使用await 可以解决这个问题。
  • 所以这是一个多线程问题而不是异步/等待问题。您似乎根本不应该使用等待/异步。如果您尝试在另一个线程上执行方法以保持 UI 线程处于活动状态。如果是这种情况,您需要更新您的问题。
  • 另一种选择,虽然我不会说它更好:dotnetfiddle.net/YzS2De

标签: c# async-await


【解决方案1】:

信号量是要走的路,但你可以让它比你的小提琴例子简单一点;像这样:

static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);

public static async Task MethodAsync()
{
    Console.Write("<");

    if (await semaphore.WaitAsync(TimeSpan.Zero))
    {
         MethodA();
         await MethodB();
         MethodC();
         semaphore.Release();
    }

    Console.Write(">");
}

【讨论】:

  • I'd like to have [...] the second call wait (asynchronously) until the first call has finished 除非我记错了,否则您的回答不满足此要求,第二次通话将立即退出
  • 想要拥有的东西实际上被错误地描述了。这应该说的是我想要一个单一方法的功能队列,以便它只被调用一次。
  • @KevinGosse - 据我了解,如果事件触发并且前一个事件仍在处理中,他实际上希望跳过整个MethodAsync()。 @OP - 如果不是,请进一步澄清。
  • 我不会说跳过,听起来他想要它排队。那么这就引出了一个问题,可以排队多少人?
  • 如果排队,他可以删除TimeSpan.Zeroif :) 小提琴中的计数器代码让我觉得他想跳过它,不过......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多