始终取消Async CancellationTokenSource的最佳做法

时间:2012-07-07 00:10:10

标签: c# asynchronous async-await cancellationtokensource

所以我的UI上有一个组合框,在SelectionChanged上它异步地转到Web服务,以撤回一些要在UI上显示的信息(使用新的C#5 async / await关键字)。我要做的是在发送新的异步请求之前取消当前的异步请求;例如,如果用户使用键盘快速遍历所有组合框项目,则在第一个异步请求返回之前,SelectionChanged事件可能会多次触发(生成多个异步请求)。

因此,从组合框的SelectionChanged事件中调用的异步函数如下所示:

public async Task<Connections> ConnectionsAsync()
{
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token);
}

其中Connections是一个关闭并触及Web服务的属性。因为一旦取消,CancellationTokenSource就无法重用,我想这样做:

public async Task<Connections> ConnectionsAsync()
{
    _cancellationTokenSource.Cancel();
    _cancellationTokenSource = new CancellationTokenSource();
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token);
}

问题是,有时我会在没有异步命令运行时调用Cancel()(例如第一次调用此函数);因此,如果我连接任何取消事件处理程序,它们将被调用,甚至在我发出异步请求之前。

无论如何都要检查异步请求是否已经在运行?除了我做的事情:

public async Task<Connections> ConnectionsAsync()
{
    if (_runningAsyncCommand)
        _cancellationTokenSource.Cancel();
    _cancellationTokenSource = new CancellationTokenSource();
    _runningAsyncCommand = true;
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token);
    _runningAsyncCommand = false;
}

我有一些异步函数都使用相同的CancellationTokenSource,所以我必须在所有这些函数中实现这个“管道”。这是最好的方法吗?或者,还有更好的方法?

另外,如果我公开公开_cancellationTokenSource以便其他类可以使用它注册取消委托,那么将这些委托“转移”到新的CancellationTokenSource的最佳方法是什么,因为我每次都创建一个新的? / p>

提前致谢!

1 个答案:

答案 0 :(得分:2)

看起来像是在天堂进行Reactive Extensions的比赛。在创建任务之前观察Combobox中的事件时,定义必须经过的节流时间(比如说300mS)

订阅TextBox更改事件的代码段,但您会明白:

var input (from evt in Observable.FromEvent<EventArgs>(txt, "TextChanged")
select ((TextBox)evt.Sender).Text)
.Throttle(TimeSpan.FromSeconds(1))
.DistinctUntilChanged();

using (input.Subscribe(inp => Console.WriteLine("You wrote: " + inp)))
{
  // Do stuff
}