Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何确保异步任务方法调用同步执行_C#_Multithreading_Async Await_Task_Task Parallel Library - Fatal编程技术网

C# 如何确保异步任务方法调用同步执行

C# 如何确保异步任务方法调用同步执行,c#,multithreading,async-await,task,task-parallel-library,C#,Multithreading,Async Await,Task,Task Parallel Library,嗨,我有文本框,它有文本更改事件。每次在文本框中插入字符时,都会触发文本更改事件。文本更改事件调用异步任务方法。下面是我的事件和异步任务方法 public Textbox_TextChangedEvent() { GetStocks(texboxText); } public async Task GetStocks(string texboxText) { IsBusy = true; await Task.Run(()

嗨,我有文本框,它有文本更改事件。每次在文本框中插入字符时,都会触发文本更改事件。文本更改事件调用异步任务方法。下面是我的事件和异步任务方法

public Textbox_TextChangedEvent()
    {
        GetStocks(texboxText);
    }

public async Task GetStocks(string texboxText)
    {
        IsBusy = true;
        await Task.Run(() => { CreateCollection(texboxText); });
        IsBusy = false;
    }
问题 如何确保一个接一个地同步调用GetStocks方法

示例 假设用户将input
Ted
作为输入文本。然后我希望异步调用一个接一个地完成。 i、 e它应该按照下面的顺序调用GetStocks,并按照下面的顺序自己完成任务

  • GetStocks(T)
  • GetStocks(Te)
  • GetStocks(Ted)

  • 根据具体情况,一个简单的选择可能是:

    public async Task GetStocks(string texboxText)
    {
        Task.Run(() => { 
           IsBusy = true;
           CreateCollection(texboxText); 
           IsBusy = false;
    
        });
    }
    

    为了解决这样的问题,我们在以前的项目中使用了
    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);
       }
    }
    
    下面是一个使用示例:

    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();
       }
    }
    

    期望的行为与当前的行为有何不同?您使用的是什么框架?这是桌面应用程序还是web应用程序?啊,如果您想将工作排队,请使用队列存储要完成的工作,然后按顺序处理。我正在使用.Net framework和WPF应用程序。抱歉,上面的代码对我不起作用。实际上,我在这里面临的问题是,按照我问题中提到的顺序,进行了三个异步调用,1.GetStocks(T)2.GetStocks(Te)3.GetStocks(Ted)。但是我得到结果的顺序是3,2,1。但我希望结果按以下顺序返回1,2,3,这很奇怪
    ContinueWith
    inside
    EnterAsync
    。作为状态传入
    newTcs
    ,却被代理忽略?这感觉就像是试图避免关闭中途放弃的局部变量。提醒我这个
    AsyncLock
    版本(除了这个版本实际上使用状态):@KirillShlenskiy你是对的。从旧的Silverlight项目获取代码,其中此参数不是可选的。将更新答案。
    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();
       }
    }
    
    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;
        }
    }