我有一个多线程应用程序,一个CancellationToken用作共享对象.每个线程都可以触发它以告诉其他线程该作业被取消.然后一个线程进行清理并像这样处理每个对象CancellationToken.然后,如果线程尝试使用它,则会引发异常:
CancellationTokenSource已被处理.
在使用之前如何找到对象?
我有一个我想要取消的任务.
执行此操作的常规方法是使用CancellationToken.
this.task = new SpecialTask(() =>
{
for (int i = 0; i < ushort.MaxValue; i++)
{
CancelToken.ThrowIfCancellationRequested();
Console.WriteLine(i);
}
}, this.CancelToken);
Run Code Online (Sandbox Code Playgroud)
然而,在现实世界中,事情从未如此简单.我们的异步代码无法循环,它看起来像这样:
this.task = new SpecialTask(() =>
{
CancelToken.ThrowIfCancellationRequested();
Operation1();
CancelToken.ThrowIfCancellationRequested();
Operation267(CancelToken);
CancelToken.ThrowIfCancellationRequested();
object232.Operation345();
CancelToken.ThrowIfCancellationRequested();
object99.Operation44(CancelToken);
CancelToken.ThrowIfCancellationRequested();
Operation5(CancelToken);
...
CancelToken.ThrowIfCancellationRequested();
Operation...n(CancelToken);
}, this.CancelToken);
Run Code Online (Sandbox Code Playgroud)
我使用随机数作为对象和方法名称来表明无法创建任何循环.
最困扰的是我必须CancelToken.ThrowIfCancellationRequested()一遍又一遍地写同样的东西.
并且,好像这还不够,我必须拖拽CancellationToken我的代码只是为了能够在适当的时候停止长时间运行 - 根据微软的说法.
话虽如此,有没有办法可以免除这些重复的电话,这会使我的代码中毒?
我们也知道,使用时
try
{
task.Wait(cancelToken);
}
catch(OperationCancelledException)
{
}
Run Code Online (Sandbox Code Playgroud)
一个OperationCancelledException被抛出和捕获的Wait方法.但是,如果没有CancelToken.ThrowIfCancellationRequested()检查,则任务执行的长操作不会停止.
有没有办法在等待时捕获到异常时停止内部操作?
我创造了一个小包装CancellationToken和CancellationTokenSource.我遇到的问题是CancelAsync方法CancellationHelper不能按预期工作.
我遇到了这个ItShouldThrowAExceptionButStallsInstead方法的问题.要取消正在运行的任务,它会调用await coordinator.CancelAsync();,但该任务实际上没有被取消,并且不会引发异常task.Wait
ItWorksWellAndThrowsException似乎运行良好而且使用coordinator.Cancel,这根本不是异步方法.
当我CancellationTokenSource在异步方法中调用Cancel方法时,为什么没有取消任务的问题是什么?
不要让waitHandle你迷惑,这只是为了不让任务提前完成.
让代码说明一切:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace TestCancellation
{
class Program
{
static void Main(string[] args)
{
ItWorksWellAndThrowsException();
//ItShouldThrowAExceptionButStallsInstead();
}
private static void ItShouldThrowAExceptionButStallsInstead()
{
Task.Run(async () =>
{
var coordinator = new CancellationHelper();
var waitHandle = new ManualResetEvent(false);
var task = Task.Run(() =>
{
waitHandle.WaitOne();
//this works well though - …Run Code Online (Sandbox Code Playgroud) c# asynchronous task cancellationtokensource cancellation-token
所以我有这个代码:
//CancelationToken
CancellationTokenSource src = new CancellationTokenSource();
CancellationToken ct = src.Token;
ct.Register(() => Console.WriteLine("Abbruch des Tasks"));
//Task
Task t = new Task(() =>
{
System.Threading.Thread.Sleep(1000);
if (ct.IsCancellationRequested)
{
try
{
//Throw
ct.ThrowIfCancellationRequested();
}
catch (OperationCanceledException)
{
Console.WriteLine(
"ThrowIfCancellationRequested() liefert eben eine Exception");
}
}
}, ct);
//Run Task and Cancel
t.Start();
src.CancelAfter(350);
t.Wait();
// Get Information
Console.WriteLine("Canceled: {0} . Finished: {1} . Error: {2}",
t.IsCanceled, t.IsCompleted, t.IsFaulted);
Run Code Online (Sandbox Code Playgroud)
所以在这种情况下我取消了我的任务,但我的输出最后是:"取消:假.完成:真.错误:错误"
在我看来,它应该是"取消:真实.完成:假".为什么我得到这个结果?因为我试图抓住异常?
我试过没有try-catch块,但是由于OperationCanceledException,我的程序停止了.有人能帮助我吗?
我最近编写了一个异步方法,调用外部长时间运行的异步方法,所以我决定通过CancellationToken启用取消.该方法可以同时调用.
实现结合了Stephen Cleary的书" Concurrency in C#Cookbook "中描述的指数退避和超时技术,如下所示;
/// <summary>
/// Sets bar
/// </summary>
/// <param name="cancellationToken">The cancellation token that cancels the operation</param>
/// <returns>A <see cref="Task"/> representing the task of setting bar value</returns>
/// <exception cref="OperationCanceledException">Is thrown when the task is cancelled via <paramref name="cancellationToken"/></exception>
/// <exception cref="TimeoutException">Is thrown when unable to get bar value due to time out</exception>
public async Task FooAsync(CancellationToken cancellationToken)
{
TimeSpan delay …Run Code Online (Sandbox Code Playgroud) 这与我的其他问题如何取消后台打印有关.
我试图更好地理解CancellationTokenSource模型以及如何跨线程边界使用它.
我有一个主窗口(在UI线程上)后面的代码:
public MainWindow()
{
InitializeComponent();
Loaded += (s, e) => {
DataContext = new MainWindowViewModel();
Closing += ((MainWindowViewModel)DataContext).MainWindow_Closing;
};
}
Run Code Online (Sandbox Code Playgroud)
它在关闭时正确调用CloseWindow代码:
private void CloseWindow(IClosable window)
{
if (window != null)
{
windowClosingCTS.Cancel();
window.Close();
}
}
Run Code Online (Sandbox Code Playgroud)
通过选择菜单项,在后台线程上创建第二个窗口:
// Print Preview
public static void PrintPreview(FixedDocument fixeddocument, CancellationToken ct)
{
// Was cancellation already requested?
if (ct.IsCancellationRequested)
ct.ThrowIfCancellationRequested();
...............................
// Use my custom document viewer (the print button is removed).
var previewWindow = new PrintPreview(fixedDocumentSequence);
//Register the cancellation procedure …Run Code Online (Sandbox Code Playgroud) 我正在尝试将HttpClient调用的默认超时设置为5秒.
我通过这样做了CancellationTokenSource.
这是相关的代码:
var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(TimeSpan.FromSeconds(5));
var result = _httpClient.SendAsync(request, cancellationToken.Token);
Run Code Online (Sandbox Code Playgroud)
按照调用代码获取"任务被取消"错误(我在.NET 4.7控制台应用程序中测试)的预期工作,但我注意到在Fiddler中请求仍然运行1分钟,直到它最终放弃:
有人可以解释这种行为吗?
我希望在触发取消时基础请求也会被取消.
_httpClient 实例化如下: new HttpClient { BaseAddress = baseAddress }
我知道有Timeout设置,但不确定我是否应该使用它或取消令牌?我的猜测是Timeout针对非异步/等待的情况?
c# cancellationtokensource dotnet-httpclient cancellation-token
嗨,我有一个列表框 每当用户选择一个项目时,就会向网络发送一个请求 现在我想在用户选择该项目时取消之前的操作,然后开始新的操作。
我使用以下代码来做到这一点,我想知道这些代码是否工作正常。还是我应该尝试另一种方式?
private CancellationTokenSource ts = new CancellationTokenSource();
private async void Subf2mCore(CancellationToken ct)
{
HtmlDocument doc = await web.LoadFromWebAsync(url);
...
foreach (var node in doc)
{
if (!ct.IsCancellationRequested)
{
....
}
}
}
Run Code Online (Sandbox Code Playgroud)
我以这种方式运行 func
ts?.Cancel();
ts = new CancellationTokenSource();
Subf2mCore(ts.Token);
Run Code Online (Sandbox Code Playgroud) 考虑这样一个场景,您需要完成一些异步工作,并且可以在即发即弃模式下运行它。这种异步工作能够侦听取消,因此您向它传递取消令牌以便能够取消它。
在给定的时刻,我们可以决定请求取消正在进行的活动,方法是使用我们从中获取取消令牌的取消令牌源对象。
因为取消令牌源实现了IDisposable,所以我们应该尽可能地调用它的Dispose方法。这个问题的重点是确定您何时完成给定的取消令牌源。
假设您决定通过调用Cancel取消令牌源上的方法来取消正在进行的工作:在调用之前是否需要等待正在进行的操作完成Dispose?
换句话说,我应该这样做:
class Program
{
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
var token = cts.Token;
DoSomeAsyncWork(token); // starts the asynchronous work in a fire and forget manner
// do some other stuff here
cts.Cancel();
cts.Dispose(); // I call Dispose immediately after cancelling without waiting for the completion of ongoing work listening to the cancellation requests via the token
// do some other …Run Code Online (Sandbox Code Playgroud) c# task-parallel-library async-await cancellationtokensource .net-core
当我取消从浏览器到 HTTP 触发器的请求时,它不会取消,而是在 Azure 上托管时继续执行。
我的函数示例:
[FunctionName("Test")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
CancellationToken cancellationToken,
ILogger log)
{
var allCancellationTokens = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, req.HttpContext.RequestAborted);
await Task.Delay(30000, allCancellationTokens.Token);
if (allCancellationTokens.IsCancellationRequested) {
log.LogInformation("Request was cancelled!");
return new StatusCodeResult(499);
}
return new OkObjectResult("Complete");
}
Run Code Online (Sandbox Code Playgroud)
我一直在通过 Postman 和 axios 取消令牌测试取消。当我在本地运行项目并取消它时,它可以工作,但一旦发布到天蓝色,它似乎就不会取消。
我的预期结果是,OperationCanceledException如果我在执行期间取消请求,它会抛出await Task.Delay(30000, allCancellationTokens.Token);异常。但是,在检查 Azure Functions 上的日志时,似乎只是继续执行并完成该函数。
重现步骤:
c# azure cancellationtokensource cancellation-token azure-functions
c# ×10
task ×4
async-await ×2
.net ×1
.net-core ×1
asynchronous ×1
azure ×1
cancellation ×1
dispose ×1
unit-testing ×1
wpf ×1