嗨我有文本更改事件的文本框。每次在文本框中插入字符时,都会触发文本更改事件。 Text changed事件调用异步Task方法。下面是我的事件和异步任务方法。
stdio
问题 我怎样才能确保一个接一个地同步调用GetStocks方法。
示例
假设用户输入public Textbox_TextChangedEvent()
{
GetStocks(texboxText);
}
public async Task GetStocks(string texboxText)
{
IsBusy = true;
await Task.Run(() => { CreateCollection(texboxText); });
IsBusy = false;
}
作为输入文本。然后我希望异步调用一个接一个地完成。
即它应按以下顺序调用GetStocks,并按照以下顺序完成任务。
答案 0 :(得分:0)
为了解决这样的问题,我们使用了AsyncLock
之前的项目。 AsyncLock
将等到上一次锁定被释放。
AsyncLock
首先看起来有点复杂,但我希望提供的用法示例能够说明其行为。
public class AsyncLock
{
private TaskCompletionSource<object> _lastSection;
public AsyncLock()
{
_lastSection = new TaskCompletionSource<object>();
_lastSection.SetResult(null);
}
public class ReleaseLock : IDisposable
{
private readonly TaskCompletionSource<object> _tcs;
public ReleaseLock(TaskCompletionSource<object> tcs)
{
_tcs = tcs;
}
public void Dispose()
{
_tcs.SetResult(null);
}
}
/// <summary>
/// Enters and locks a critical section as soon as the currently executing task has left the section.
/// The critical section is locked until the returned <see cref="IDisposable"/> gets disposed.
/// </summary>
public Task<ReleaseLock> EnterAsync()
{
var newTcs = new TaskCompletionSource<object>();
var toAwait = Interlocked.Exchange(ref _lastSection, newTcs);
return toAwait.Task.ContinueWith((_) => new ReleaseLock(newTcs), TaskContinuationOptions.ExecuteSynchronously);
}
}
然后,您可以使用await AsyncLock.EnterAsync()
等待,直到释放任何先前的锁定。在EnterAsync
我们使用Task
将当前Task
后的ContinueWith
排队。这意味着await AsyncLock.EnterAsync()
将在前一个完成后执行。
using (await _lock.EnterAsync())
{
// ...
}
以下是一个用法示例:
class Program
{
private static readonly AsyncLock _lock = new AsyncLock();
private static async Task Test(int i, Task toComplete)
{
using (await _lock.EnterAsync())
{
await toComplete;
Console.WriteLine(i);
}
}
public static void Main(string[] args)
{
var tcs1 = new TaskCompletionSource<object>();
var tcs2 = new TaskCompletionSource<object>();
Task.Run(async () =>
{
var t1 = Test(1, tcs1.Task); // start first task
var t2 = Test(2, tcs2.Task); // start second task
tcs2.SetResult(null); // finish second first
tcs1.SetResult(null); // fiish last task
await Task.WhenAll(t1, t2); // will print: 1 and then 2
}).Wait();
}
}
Test
方法将首先进入Async
锁定,然后等待任务toComplete
,然后写入控制台。
我们开始执行两项Test
任务(&#34; 1&#34; ,&#34; 2&#34; )并完成第二项任务toComplete
首先。如果没有AsyncLock
上一个示例,则打印:&#34; 2&#34; ,&#34; 1&#34; 。然而,使用AsyncLock
,任务将按照启动顺序进行处理。
备注:最后一句话。这将实现您的处理顺序,但有时可能会很棘手。使用这样的锁很容易导致死锁,这些死锁很难解决,而且最初难以找到。 非常小心地使用锁。
编辑:以下是您的问题的用法示例:
private readonly AsyncLock _lock = new AsyncLock();
public Textbox_TextChangedEvent()
{
GetStocks(texboxText); // every call is now "queued" after the previous one
}
public async Task GetStocks(string texboxText)
{
using(await _lock.EnterAsync())
{
IsBusy = true;
await Task.Run(() => { CreateCollection(texboxText); });
IsBusy = false;
}
}
答案 1 :(得分:-1)
根据具体情况,一个简单的选择可能是:
public async Task GetStocks(string texboxText)
{
Task.Run(() => {
IsBusy = true;
CreateCollection(texboxText);
IsBusy = false;
});
}