重入在异步/等待? [英] Reentrancy in async/await?

查看:118
本文介绍了重入在异步/等待?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有具有对异步方法调用等待着一个异步处理程序的按钮。下面是它的样子:

I have a button which has an async handler which calls awaits on an async method. Here's how it looks like:

private async void Button1_OnClick(object sender, RoutedEventArgs e)
{
    await IpChangedReactor.UpdateIps();
}

下面是如何 IpChangedReactor.UpdateIps()的样子:

public async Task UpdateIps()
{
    await UpdateCurrentIp();
    await UpdateUserIps();
}

这是异步一路下滑。结果
现在我有一个 DispatcherTimer 其中反复调用在其Tick事件等待IpChangedReactor.UpdateIps

比方说,我点击的按钮。现在,事件处理程序等待上 UpdateIps 并返回到调用程序,这意味着WPF将继续做其他的事情。在此期间,如果计时器所触发,它会再次调用 UpdateIps ,现在这两种方法会同时运行。所以我看到它的方式是,它是类似于使用2个线程。可以比赛情况发生呢? (我的一部分说,没有,因为它是在同一个线程运行的。但它的混乱)

Let's say I clicked the button. Now the event handler awaits on UpdateIps and returns to caller, this means that WPF will continue doing other things. In the meantime, if the timer fired, it would again call UpdateIps and now both methods will run simultaneously. So the way I see it is that it's similar to using 2 threads. Can race conditions happen? (A part of me says no, because it's all running in the same thread. But it's confusing)

我知道异步方法不一定在单独的线程运行。然而,在这种情况下,它是pretty混乱。

I know that async methods doesn't necessarily run on separate threads. However, on this case, it's pretty confusing.

如果我在这里使用同步方法,它会如预期的工作。第一次调用完成后,计时器滴答事件只运行。

If I used synchronous methods here, it would have worked as expected. The timer tick event will run only after the first call completed.

有人能告诉我吗?

推荐答案

由于这两个调用在UI线程运行的code是在传统意义上的线程安全 - 不会有任何异常或损坏数据。

Since both calls run on the UI thread the code is "thread safe" in the traditional sense of - there wouldn't be any exceptions or corrupted data.

然而,才会有合理的竞争条件?当然。你可以很容易有这种流(或任何其他):

However, can there be logical race conditions? Sure. You could easily have this flow (or any other):

UpdateCurrentIp() - button
UpdateCurrentIp() - Timer
UpdateUserIps() - Timer
UpdateUserIps() - button

该方法的名称好像不是真的是一个问题,但是这取决于实际执行这些方法。

By the method names it seems not to really be an issue but that depends on the actual implementation of these methods.

一般来说,你可以使用可以避免通过同步调用这些问题的 SemaphoreSlim AsyncLock How保护可在多线程或异步环境中使用资源的):

Generally you can avoid these problems by synchronizing calls using a SemaphoreSlim, or an AsyncLock (How to protect resources that may be used in a multi-threaded or async environment?):

using (await _asyncLock.LockAsync())
{
    await IpChangedReactor.UpdateIps();
}

在此情况下,虽然,它似乎简单地避免启动时,一个是当前正在运行一个新的更新是不够好:

In this case though, it seems that simply avoiding starting a new update when one is currently running is good enough:

if (_isUpdating) return;

_isUpdating = true;
try
{
    await IpChangedReactor.UpdateIps();
}
finally
{
    _isUpdating = false;
}

这篇关于重入在异步/等待?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆