我有一个框架,它创建 CancellationTokenSource,配置 CancelAfter,然后调用异步方法并传递令牌。然后,异步方法会生成许多任务,将取消令牌传递给每个任务,然后等待任务的集合。这些任务均包含通过轮询 IsCancellationRequested 正常取消的逻辑。
我的问题是,如果我将 CancellationToken 传递到 Task.Run() 中,则会引发包含 TaskCanceledException 的 AggregateException。这会阻止任务正常取消。
为了解决这个问题,我无法将 CancelationToken 传递到 Task.Run 中,但是我不确定我会失去什么。例如,我喜欢这样的想法:如果我的任务挂起并且无法执行正常取消,则此异常将强制其停止。我想我可以串联两个 CancelationTokens 来处理这个问题,一个“优雅”,另一个“强制”。但是,我不喜欢这个解决方案。
这是一些代表我上面描述的内容的伪代码。
public async Task Main()
{
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(30000);
await this.Run(cts.Token);
}
public async Task Run(CancellationToken cancelationToken)
{
HashSet<Task> tasks = new HashSet<Task>();
foreach (var work in this.GetWorkNotPictured)
{
// Here is where I could pass the Token,
// however If I do I cannot cancel gracefully
// My dilemma here is by not passing I lose …Run Code Online (Sandbox Code Playgroud) c# multithreading asynchronous async-await cancellationtokensource
try
{
ParallelOptions Options = new ParallelOptions();
Options.CancellationToken = base.DownloadCancellation.Token;
Parallel.ForEach(base.BlockingCollection1, Options, ActiveSeeder =>
{
//...
});
}
catch
{
if (base.DownloadCancellation.IsCancellationRequested)
return false;
}
Run Code Online (Sandbox Code Playgroud)
Parallel.Foreach/For 是否使用或不使用我放入 ParallelOptions 的 CancellationToken 调用 BlockingCollection1.Take 函数?
有机会知道吗?
c# multithreading cancellationtokensource parallel.foreach blockingcollection
我想使用CancellationToken中止文件下载.这是我试过的:
public async Task retrieveDocument(Document document)
{
// do some preparation work first before retrieving the document (not shown here)
if (cancelToken == null)
{
cancelToken = new CancellationTokenSource();
try
{
Document documentResult = await webservice.GetDocumentAsync(document.Id, cancelToken.Token);
// do some other stuff (checks ...)
}
catch (OperationCanceledException)
{
Console.WriteLine("abort download");
}
finally
{
cancelToken = null;
}
}
else
{
cancelToken.Cancel();
cancelToken = null;
}
}
public async Task<Document> GetDocumentAsync(string documentId, CancellationToken cancelToken)
{
Document documentResult = new …Run Code Online (Sandbox Code Playgroud) 我有一些Task.Run与取消令牌一起使用的代码。
这是我的代码:
public class TaskObject
{
CancellationTokenSource _source = new CancellationTokenSource();
public async Task TaskAction()
{
var task = Task.Run(async delegate
{
await TaskRun();
}, _source.Token);
//TaskCancel();
try
{
task.Wait();
}
catch (Exception ex)
{
}
}
public async Task TaskRun()
{
if (_source.IsCancellationRequested)
{
_source.Token.ThrowIfCancellationRequested();
}
SpeechSynthesizer _speechSynthesizer = new SpeechSynthesizer();
_speechSynthesizer.SpeakAsync("This is a test prompt");
}
public void TaskCancel()
{
_source.Cancel();
}
}
Run Code Online (Sandbox Code Playgroud)
如果我调用TaskCancel()中的TaskAction(),则会捕获任务取消异常。
TaskCancel()如果我从对象外部调用,则不会捕获已取消的异常。
以下是一些代码,用于演示未捕获已取消异常的位置:
taskObject = new TaskObject();
await …Run Code Online (Sandbox Code Playgroud) 我尝试使用如下所示的超时编写一个简单的异步写入,并期望该函数在给定非常大的缓冲区和小waitTime时抛出TaskCanceledException.但是,这不会发生.WriteAsync将阻塞很多秒,直到写入完成.我错过了什么?
public async void WriteWithTimeout(Stream os, byte[] buf, int waitMs)
{
CancellationTokenSource tokenSource = new CancellationTokenSource(waitMs); // cancel after waitMs milliseconds.
await os.WriteAsync(buf, 0, buf.Length, tokenSource.Token);
return;
}
Run Code Online (Sandbox Code Playgroud)
从GUI线程调用:
try
{
WriteWithTimeout(response.OutputStream, buf100M, w1ms);
}
catch(OperationCanceledException e)
{
ConsoleWriteLine("Failed with exception: {0}", e.Message);
}
Run Code Online (Sandbox Code Playgroud) 对于在以下情况下如何实现取消标记,我有些困惑。
说我有一个方法,它有一个取消令牌,没有指定超时,像这样。
public static async Task DoSomeAsyncThingAsync(CancellationToken cancellationToken = default)
{
try
{
Task.Delay(1000, cancellationToken)
}
catch (OperationCanceledException canceledException)
{
// Do something with canceledException
Console.WriteLine("DoSomeElseAsyncThingAsync {0}", canceledException);
throw;
}
catch (Exception exception)
{
// Do something with exception
Console.WriteLine("DoSomeElseAsyncThingAsync {0}", exception);
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
但是在该方法中,我想调用另一个期望CancellationToken除此以外的方法,但这次我要对此设置超时。
public static async Task DoSomeAsyncThingAsync(CancellationToken cancellationToken = default)
{
try
{
var innerCancellationTokenSource = new CancellationTokenSource();
innerCancellationTokenSource.CancelAfter(1000);
var innerCancellationToken = innerCancellationTokenSource.Token;
await DoSomeElseAsyncThingAsync(innerCancellationToken);
}
catch (OperationCanceledException canceledException)
{
// Do something with …Run Code Online (Sandbox Code Playgroud) c# cancellation async-await cancellationtokensource cancellation-token
我有创建 CancellationTokenSource 并将其传递给方法的代码。
我在另一个发出 cts.Cancel(); 的应用程序中有代码。
有没有一种方法可以使该方法立即停止,而不必等待 while 循环内的两行完成?
请注意,如果它导致我可以处理的异常,我会没事的。
public async Task OnAppearing()
{
cts = new CancellationTokenSource();
await GetCards(cts.Token);
}
public async Task GetCards(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
App.viewablePhrases = App.DB.GetViewablePhrases(Settings.Mode, Settings.Pts);
await CheckAvailability();
}
}
Run Code Online (Sandbox Code Playgroud) 在获取CancellationToken( StartAsync) 的方法内部,我想添加一个内部函数CancellationToken,以便调用者可以在外部或内部取消异步操作(例如,通过调用方法AbortAsync())。
AFAIK,这样做的方法是使用CreateLinkedCancellationTokenSource. 但它的 API 似乎相当不舒服,因为我需要为此创建两个额外的实例,并且因为它们实现了,所以我也必须不要忘记处置它们。因此,我需要将它们都存储为成员以供以后处理。CancellationTokenSourceIDisposable
我错过了什么吗?我觉得应该有一种更简单的方法来将额外的取消机制附加到现有令牌上,而不会迫使我维护两个CancellationTokenSource实例。
public Task StartAsync(CancellationToken externalToken)
{
this.actualCancellation = new CancellationTokenSource();
this.linkedCancellation = CancellationTokenSource.CreateLinkedTokenSource(
actualCancellation.Token, externalToken);
this.execution = this.ExecuteAsync(this.linkedCancellation.Token);
return this.execution;
}
public async Task AbortAsync()
{
try
{
this.actualCancellation.Cancel();
await this.execution;
}
catch
{
}
finally
{
this.actualCancellation.Dispose();
this.linkedCancellation.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud) 创建 CancellationToken 时使用 TimeSpan.FromMilliseconds(1000) 而不是使用常量值有什么优势吗?
CancellationTokenSource ctsTs = new(TimeSpan.FromMilliseconds(1000));
CancellationTokenSource ctsConst = new(1000);
Run Code Online (Sandbox Code Playgroud) 拥有这个处理程序:
public async Task<Result> Handle(MyQuery request, CancellationToken cancellationToken)
{
var cancellationTokenSource = new CancellationTokenSource();
await Parallel.ForEachAsync(myList, async (objectId, _) =>
{
var result = await _service.GetObject(objectId);
if (result.Any())
{
cancellationTokenSource.Cancel();
}
});
if (cancellationTokenSource.IsCancellationRequested) return Result.Fail("Error message.");
return Result.Ok();
}
Run Code Online (Sandbox Code Playgroud)
这可行,但想知道我CancellationTokenSource在这里使用是否正确?
.net c# async-await cancellationtokensource parallel.foreachasync
我想取消一个线程,然后再运行另一个线程.这是我的代码:
private void ResetMedia(object sender, RoutedEventArgs e)
{
cancelWaveForm.Cancel(); // cancel the running thread
cancelWaveForm.Token.WaitHandle.WaitOne(); // wait the end of the cancellation
cancelWaveForm.Dispose();
//some work
cancelWaveForm = new CancellationTokenSource(); // creating a new cancellation token
new Thread(() => WaveFormLoop(cancelWaveForm.Token)).Start(); // starting a new thread
}
Run Code Online (Sandbox Code Playgroud)
当我调用这个方法时,第一个线程不会停止而第二个线程开始运行...
但是如果我跳过最后两行它会工作:
private void ResetMedia(object sender, RoutedEventArgs e)
{
cancelWaveForm.Cancel(); // cancel the running thread
cancelWaveForm.Token.WaitHandle.WaitOne(); // wait the end of the cancellation
cancelWaveForm.Dispose();
//some work
//cancelWaveForm = new CancellationTokenSource(); // creating a new cancellation …Run Code Online (Sandbox Code Playgroud) c# multithreading cancellationtokensource cancellation-token
我在掌握任务和取消令牌方面遇到了一些问题.我做了一个看起来像这样的程序:
static void Main(string[] args)
{
CancellationTokenSource token = new CancellationTokenSource();
Stopwatch stop = new Stopwatch();
stop.Start();
for (int i = 0; i < 5; i++)
{
//Thread.Sleep(1000);
Task.Factory.StartNew(() => myLongTask(token.Token, (i + 1) * 1000));
}
while (true)
{
Thread.SpinWait(1000);
if (stop.ElapsedMilliseconds > 3000)
{
token.Cancel();
}
}
}
public static void myLongTask(CancellationToken token, int time)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Cancelled");
return;
}
var sw = Stopwatch.StartNew();
Console.WriteLine($"Task {time / 1000} started");
while (sw.ElapsedMilliseconds < time)
Thread.SpinWait(1000);
Console.WriteLine($"Task {time …Run Code Online (Sandbox Code Playgroud) 我收到了一项可以同时执行多项任务的服务。我被分配添加一个中止选项,该选项应该结束所有当前正在运行的任务。因为系统已经实现,所以将 CancellationTokenSource 传递给每个任务是有问题的,所以我所做的是创建一个所有任务都会侦听取消的单个令牌。当中止接收时,该令牌将发送取消,然后将创建一个新的 CancellationTokenSource 实例。我无法验证所有任务,直到中止之前结束在 启动 CancellationTokenSource 的新实例
几个问题:
起初我以为 TokenSource.Cancel() 只是一个发送的事件,但它似乎被卡在“高位”,所以任何具有相同令牌的新任务也会收到取消,是真的吗?
理想情况下,每个任务都有自己的取消令牌(对吗?),问题是谁需要持有该令牌?谁调用了该任务或任务本身?因为一旦发送取消,我将需要永远保留该令牌,因为我无法判断任务何时到达退出点。
是否有一种已经实现的方法来监视所有当前正在运行的任务,以便在发送取消时我将确保在允许任何新任务之前所有任务都已结束?我使用信号量做到了这一点,但它看起来像是一个糟糕的解决方案。
对于新手问题,我很抱歉,我已经实现了我需要的内容并且它有效,但质量远低于标准,我希望以正确的方式改进它。
c# ×13
async-await ×5
.net ×3
task ×3
asynchronous ×2
.net-core ×1
cancellation ×1
outputstream ×1
threadpool ×1