- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
首先,请原谅我的英语。我将在 Task.WhenAny 之后的附加代码中进行简要说明,我期望的是五个任务中至少有三个将被取消,但都圆满结束。当任务被取消时,SemaphoreSlim.WaitAsync 不会抛出 OperationCanceledException。
class Program
{
private static CancellationTokenSource methodRequests = new CancellationTokenSource();
private static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
static void Main(string[] args)
{
int[] delays = new int[] { 5000, 5010, 5020, 5030, 5040 };
IEnumerable<Task> tasks = from delay in delays select MethodAsync(delay, new CancellationTokenSource().Token);
Task.WhenAny(tasks).Wait();
methodRequests.Cancel();
Console.ReadKey();
}
static async Task MethodAsync(int milliseconds, CancellationToken cancellationToken)
{
var methodRequest = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, methodRequests.Token);
try
{
await semaphore.WaitAsync(methodRequest.Token);
Thread.Sleep(milliseconds);
Console.WriteLine($"Task finished {milliseconds}");
}
catch (OperationCanceledException)
{
Console.WriteLine($"Task canceled {milliseconds}");
}
finally
{
semaphore.Release();
}
}
}
我做错了什么?
谢谢。
最佳答案
您的代码中的问题是 MethodAsync()
方法在 Thread.Sleep()
方法完成之前永远不会返回。这意味着在前一个任务完成之前,每个任务甚至都不会开始。这是您的代码版本,可以更清楚地说明这一点:
private static CancellationTokenSource methodRequests = new CancellationTokenSource();
private static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
static void Main(string[] args)
{
int[] delays = new int[] { 5000, 5010, 5020, 5030, 5040 };
IEnumerable<Task> tasks = from delay in delays select MethodAsync(delay, new CancellationTokenSource().Token);
Task.WhenAny(tasks).Wait();
methodRequests.Cancel();
ReadKey();
}
static async Task MethodAsync(int milliseconds, CancellationToken cancellationToken)
{
var methodRequest = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, methodRequests.Token);
try
{
WriteLine($"waiting semaphore (will wait {milliseconds} ms)");
await semaphore.WaitAsync(methodRequest.Token);
WriteLine($"waiting {milliseconds} ms");
Thread.Sleep(milliseconds);
WriteLine($"Task finished {milliseconds}");
}
catch (OperationCanceledException)
{
WriteLine($"Task canceled {milliseconds}");
}
finally
{
semaphore.Release();
}
}
输出是:
waiting semaphore (will wait 5000 ms)waiting 5000 msTask finished 5000waiting semaphore (will wait 5010 ms)waiting 5010 msTask finished 5010waiting semaphore (will wait 5020 ms)waiting 5020 msTask finished 5020waiting semaphore (will wait 5030 ms)waiting 5030 msTask finished 5030waiting semaphore (will wait 5040 ms)waiting 5040 msTask finished 5040
如您所见,在上一个任务完成之前,您甚至都不会看到“正在等待信号量...” 消息。这是因为在 MethodAsync()
方法返回当前元素的值之前,您的 LINQ select
无法继续处理序列中的下一个元素,并且直到Thread.Sleep()
完成。
您可能认为 await semaphore.WaitAsync()
应该让步给调用者,允许返回 Task
和 select 的枚举
继续。但是,只有在信号量不可用时才会发生这种情况。它在每次调用时都可用,因为每次调用仅在前一个调用完成后发生,因为在进行前一个调用时,信号量可用。由于在调用 WaitAsync()
时信号量可用,因此 await
同步完成。 IE。代码直接进入 Thread.Sleep()
而不是让步给调用者。
最终效果是 WhenAny()
的调用甚至不会发生,直到 all Thread.Sleep()
调用(当然,所有 semaphore.WaitAsync()
调用也已完成)。
大概这是在某些真实场景中出现的,您发布的代码仅用于演示目的。因此,很难准确地说出您应该修复什么。但是,在您发布的代码示例中,只需切换到 Task.Delay()
而不是 Thread.Sleep()
就足够了。由于延迟始终不为零,因此该方法将始终在该点产生,即使信号量本身可用。这允许 select
在当前调用中的“工作”完成之前继续对 MethodAsync()
的下一次调用。
通过这种方式,所有任务实际上都按照您最初的预期同时创建。
无论现实世界的代码是什么样子,您要做的是确保在获取信号量后有一个异步操作,以允许该方法实际返回给调用者,以便下一个操作( s) 也可以启动。
关于C#。取消任务时,SemaphoreSlim.WaitAsync 不会抛出 OperationCanceledException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48254614/
我正在尝试向 URL 发出异步 Web 请求,该请求将在请求时间过长时返回。我正在使用 F# 异步工作流和 System.Net.Http 库来执行此操作。 但是,我无法在 async 中捕获 Sys
我得到一个TaskCanceledException: 然后我将此异常作为 Exception 传递给另一个方法。如果我检查类型 if (ex.GetType() == typeof(Operatio
我的同事玩过 TPL 和任务取消。他向我展示了以下代码: var cancellationToken = cts.Token; var task = Task.Run(() => { whil
我有一个 Azure Function (.net 6.0),它从服务总线接收消息。 99% 的消息处理得很好,但时不时地我会在 Application Insights 中收到 System.Ope
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 6 年前。 Improve this qu
我正在实现一个 Parallel.ForEach 循环来做一些工作,但由于未处理的异常,我遇到了一个问题,而我认为我处理了取消。 为了尝试解决问题,我在 winform 中做了一个简单的测试设置。它有
我有一些代码要从 .NET 4.5 的可爱 async 和 await 关键字降级到 .NET 4.0。我正在使用 ContinueWith 创建一个类似于 await 工作方式的延续。 基本上,我的
以下代码创建了一个被取消的任务。 await 表达式(案例 1)抛出 System.OperationCanceledException 而同步 Wait()(案例 2)抛出 System.Threa
OperationCanceledException 和 TaskCanceledException 有什么区别?如果我使用 .NET 4.5 并使用 async/await 关键字,我应该寻找哪个?
我正在使用一个支持取消的异步 api,我正在向该 api 传递一个 CancellationToken实例。像往常一样,如果在传递的 token 上请求取消,我正在调用的 api 将抛出 Operat
我有来自“.NET Framework 并行编程示例”的以下代码 MSDN当我试图在 Debug模式下取消猴子的遗传生成时,我在 token.ThrowIfCancellationRequested(
当用户加载页面时,它会发出一个或多个 ajax 请求,这些请求会命中 ASP.NET Web API 2 Controller 。如果用户导航到另一个页面,在这些 ajax 请求完成之前,浏览器会取消
我正在遵循示例代码 here了解异步任务。我修改了代码以编写任务工作与主要工作的一些输出。输出将如下所示: 我注意到,如果我删除 Wait() 调用,程序运行相同,只是我无法捕获任务取消时抛出的异常。
首先,请原谅我的英语。我将在 Task.WhenAny 之后的附加代码中进行简要说明,我期望的是五个任务中至少有三个将被取消,但都圆满结束。当任务被取消时,SemaphoreSlim.WaitAsyn
我有一个长时间运行的操作,我想在 5 秒后取消。不幸的是,无法轮询 IsCancellationRequested(长话短说)。 我使用下面的代码在取消回调中抛出一个 OperationCancele
考虑以下代码: CancellationTokenSource cts0 = new CancellationTokenSource(), cts1 = new CancellationTokenSo
我试图允许取消 Parallel.ForEach 循环。根据this MSDN article ,这是可能的,我正在按照他们的编码进行操作。 // Tokens for cancellation Pa
我正在使用 BlockingCollection 来实现任务调度程序,基本上: public class DedicatedThreadScheduler : TaskScheduler, IDisp
我正在使用(坦率地说很棒)BlockingCollection键入大量多线程的高性能应用。 集合的吞吐量很大,在微观层面上它的性能很高。但是,对于每个“批处理”,它将始终通过标记取消 token 来结
我使用 Async.Catch 来处理异步工作流抛出的异常: work |> Async.Catch |> Async.RunSynchronously |> fun x -> match x wit
我是一名优秀的程序员,十分优秀!