wpf 异步/等待的争用情况,如何解决

pnwntuvh  于 2022-11-18  发布在  其他
关注(0)|答案(3)|浏览(144)

我有一个问题与async/await在C#,我需要它来获得一些对象称为交易,在我得到它,它需要保存它。问题是,与async/await,它是做保存第一,然后去,并获得我的交易对象。我如何确保我得到的对象第一,然后做保存....这是我的代码...

private async void OnRefresh()
    {
        try
        {
            var trades = await ExchangeServiceInstance.GetTrades("");
            mmTrades = new ObservableCollection<EEtrade>(trades);
            tradeListView.ItemsSource = mmTrades;
        }
        catch { }
    }

    public async void OnSignalReceived()
    {
        // THIS NEEDS TO FINISH FIRST, BUT IT DOESN'T
        await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
        {
            if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
            {
                await Task.Delay(MMConfig.DELAYMILLISEC);
                OnRefresh();
            }
        });

        // SOMEHOW THIS GETS CALLED FIRST BEFORE THE ABOVE GETS TO FINISH!
        await OnSaveTrades();
    }

    public async Task<int> OnSaveTrades()
    {
        foreach (var trade in mmTrades)
        {
            await ExchangeServiceInstance.OnInsertDoneTrade(trade);
        }
        return mmTrades.Count;
    }

有什么想法吗?谢谢!

9lowa7mx

9lowa7mx1#

问题出在您的OnRefresh方法上。因为返回类型是void,所以没有等待该方法[ Check out this answer ]。此外,您甚至没有尝试等待委托内的方法
将方法更改为以下内容:

private async Task OnRefresh()
    {
        try
        {
            var trades = await ExchangeServiceInstance.GetTrades("");
            mmTrades = new ObservableCollection<EEtrade>(trades);
            tradeListView.ItemsSource = mmTrades;
        }
        catch { }
    }

而在你的委托里面等待这个方法,应该可以解决你的问题:

public async void OnSignalReceived()
    {
        // THIS NEEDS TO FINISH FIRST, BUT IT DOESN'T
        await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
        {
            if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
            {
                await Task.Delay(MMConfig.DELAYMILLISEC);
                await OnRefresh();
            }
        });

        // SOMEHOW THIS GETS CALLED FIRST BEFORE THE ABOVE GETS TO FINISH!
        await OnSaveTrades();
    }
5q4ezhmt

5q4ezhmt2#

(Action)async的用法基本上与async void相同,async void * 几乎总是 * 一个错误。特别地,消费者不能知道结果(除非它同步出错)。这里的调度程序 * 并没有真正考虑async *。
如果我们假设您必须在这里使用调度程序,那么一种 * 变通方法 * 可能是使用类似于SemaphoreSlim(或者可能是TaskCompletionSource<something>)的东西,您 * 在异步工作结束 * 时发出信号(即使是在异常情况下),然后等待 * 该 *;未经测试,但是:

var tcs = new TaskCompletionSource<bool>();
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
    try {
        if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
        {
            await Task.Delay(MMConfig.DELAYMILLISEC);
            OnRefresh();
        }
        tcs.TrySetResult(true);
    } catch (Exception ex) {
        tcs.TrySetException(ex);
    }
});
await tcs.Task; // ensure the async work is complete

await OnSaveTrades();
ilmyapht

ilmyapht3#

首先,你经常使用async void模式。这对于number of reasons来说是很糟糕的做法。你应该停止这样做。
这里的问题是OnRefresh又是一个异步void方法,它不能等待,但应该是:

private async Task OnRefresh()
{
    try
    {
        var trades = await ExchangeServiceInstance.GetTrades("");
        mmTrades = new ObservableCollection<EEtrade>(trades);
        tradeListView.ItemsSource = mmTrades;
    }
    catch { }
}

OnSignalReceived方法中,将对OnRefresh();的调用更改为await OnRefresh();

相关问题