C# 跟踪并取消以前的任务';执行新排队任务时的s CancellationTokens
我请求对以下内容进行代码审查,这超出了我的正常范围,我想知道算法是否正确?其目的是跟踪添加到后台工作队列的任务的取消令牌。它应该首先对所有现有令牌调用cancel,将自己的令牌添加到ConcurrentBag,然后执行工作。谢谢 编辑:基本上我是在问,这是正确的吗?在此方法中执行的较新任务(在C# 跟踪并取消以前的任务';执行新排队任务时的s CancellationTokens,c#,asp.net,asp.net-web-api,parallel-processing,task-parallel-library,C#,Asp.net,Asp.net Web Api,Parallel Processing,Task Parallel Library,我请求对以下内容进行代码审查,这超出了我的正常范围,我想知道算法是否正确?其目的是跟踪添加到后台工作队列的任务的取消令牌。它应该首先对所有现有令牌调用cancel,将自己的令牌添加到ConcurrentBag,然后执行工作。谢谢 编辑:基本上我是在问,这是正确的吗?在此方法中执行的较新任务(在while中)是否会取消在//网络请求时暂停的较旧任务,从而防止不必要的工作//将作为集合的缓存项重新水化只需由最新执行的任务(不是每个执行的任务)运行一次 公共类管理器{ 私有静态只读Concurrent
while
中)是否会取消在//网络请求时暂停的较旧任务,从而防止不必要的工作//将作为集合的缓存项重新水化
只需由最新执行的任务(不是每个执行的任务)运行一次
公共类管理器{
私有静态只读ConcurrentBag CancelTokens=新ConcurrentBag();
//下面的方法被这样调用
//HostingEnvironment.QueueBackgroundWorkItem(异步(cancelationToken)=>Wait PerformTask和CancelPreviousTasks(cancelationToken));
公共异步任务PerformTask和CancelPreviousTasks(CancellationToken ct)
{
尝试
{
//取消以前的所有任务
而(!CancelTokens.IsEmpty)
{
CancellationToken previousTaskCancelToken;
CancelTokens.TryTake(out previousTaskCancelToken);
如果(先前的TaskCancelToken.canbecancelled)
{
CancellationTokenSource.CreateLinkedTokenSource(previousTaskCancelToken).Cancel();
}
}
CancelTokens.Add(ct);//将此任务的CancellationToken添加到ConcurrentBag
//将单个缓存项重新水化
//为了提高性能,只有最新的任务需要运行此命令
如果(!ct.iscancellationrequest)
{
//将作为集合的缓存项重新水化
}
}
捕获(例外e)
{
TelemetryManager.TrackException(“PerformTask和CancelPreviousTasks中的错误”,e);
}
}
}
在修改了PerformTask和CancelPreviousTasks
方法以采用CancellationTokenSource
而不是CancellationToken
之后,我觉得它似乎起到了作用。堆积起来的电话确实会被取消
public class Program
{
static void Main(string[] args)
{
///////////////////////////////////////////////////////////////////////////////
// Test
//
// Out:
// Thread [852] performed the work
// Was last executing thread: FALSE. Was #897
// QueueUserWorkItem Call 1762
// Thread [854] performed the work
// Was last executing thread: FALSE. Was #1412
// QueueUserWorkItem Call 1391
// Thread [1836] performed the work
// Was last executing thread: TRUE. Was #2000
// QueueUserWorkItem Call 1984
//
///////////////////////////////////////////////////////////////////////////////
Manager mgr = new Manager();
// 2000 rapid updates
for (int i = 0; i < 2000; i++)
{
new Thread(new ParameterizedThreadStart((id) => {
// Thread.Sleep(2000 - (int) id);
Random rand = new Random();
Thread.Sleep(rand.Next(2, 500));
CancellationTokenSource ctSource = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(async (state) => await mgr.PerformTaskAndCancelPreviousTasks(ctSource, (int) id, rand.Next(7, 2500)));
})).Start(i);
};
Task.Delay(15000).Wait(); // Keep ThreadPool alive
}
}
public class Manager
{
private static readonly ConcurrentBag<CancellationTokenSource> CancelTokens = new ConcurrentBag<CancellationTokenSource>();
private static volatile int AtomicCounter = 0;
// Below method gets called like this
// HostingEnvironment.QueueBackgroundWorkItem(async (cancelationToken) => await PerformTaskAndCancelPreviousTasks(cancelationToken));
public async Task PerformTaskAndCancelPreviousTasks(CancellationTokenSource cts, int tN, int delay)
{
try
{
Interlocked.Increment(ref AtomicCounter);
// Cancel all previous tasks
while (!CancelTokens.IsEmpty)
{
CancellationTokenSource previousTaskCancelTokenSource = null;
CancelTokens.TryTake(out previousTaskCancelTokenSource);
if (previousTaskCancelTokenSource != null)
{
previousTaskCancelTokenSource.Cancel();
}
}
CancelTokens.Add(cts); // Add this task's CancellationToken to ConcurrentBag
await Task.Delay(delay); // Simulate network request
// Only the newest task needs to run this, for performance
if (!cts.Token.IsCancellationRequested)
{
// Rehydrate a cache item that is a collection
Console.WriteLine(string.Format("Thread [{0}] performed the work", Thread.CurrentThread.ManagedThreadId));
Console.WriteLine(string.Format("Was last executing thread: {0}. Was #{1}", AtomicCounter == 2000 ? "TRUE" : "FALSE", AtomicCounter));
Console.WriteLine(string.Format("QueueUserWorkItem Call {0}", tN));
}
}
catch (Exception e)
{
Console.WriteLine("Exception occurred in:\r\n" + e.StackTrace);
}
}
}
公共类程序
{
静态void Main(字符串[]参数)
{
///////////////////////////////////////////////////////////////////////////////
//试验
//
//输出:
//线程[852]执行了该工作
//Was最后一个执行线程:FALSE。Was#897
//QueueUserWorkItem调用1762
//线程[854]执行了该工作
//Was最后一个执行线程:FALSE。Was#1412
//QueueUserWorkItem调用1391
//线程[1836]执行了该工作
//Was最后一个执行线程:TRUE.Was#2000
//QueueUserWorkItem调用1984
//
///////////////////////////////////////////////////////////////////////////////
经理=新经理();
//2000快速更新
对于(int i=0;i<2000;i++)
{
新线程(新的参数化线程开始((id)=>{
//线程睡眠(2000-(int)id);
Random rand=新的Random();
Thread.Sleep(兰特下一步(2500));
CancellationTokenSource ctSource=新的CancellationTokenSource();
ThreadPool.QueueUserWorkItem(异步(状态)=>Wait-mgr.PerformTask和CancelPreviousTasks(ctSource,(int)id,rand.Next(72500));
}))·启动(i);
};
Task.Delay(15000.Wait();//保持线程池活动
}
}
公共班级经理
{
私有静态只读ConcurrentBag CancelTokens=新ConcurrentBag();
私有静态volatile int原子计数器=0;
//下面的方法被这样调用
//HostingEnvironment.QueueBackgroundWorkItem(异步(cancelationToken)=>Wait PerformTask和CancelPreviousTasks(cancelationToken));
公共异步任务PerformTask和CancelPreviousTasks(CancellationTokenSource cts、int tN、int delay)
{
尝试
{
联锁增量(参考原子计数器);
//取消以前的所有任务
而(!CancelTokens.IsEmpty)
{
CancellationTokenSource previousTaskCancelTokenSource=null;
CancelTokens.TryTake(out previousTaskCancelTokenSource);
if(previousTaskCancelTokenSource!=null)
{
previousTaskCancelTokenSource.Cancel();
}
}
CancelTokens.Add(cts);//将此任务的CancellationToken添加到ConcurrentBag
等待任务。延迟(延迟);//模拟网络请求
//为了提高性能,只有最新的任务需要运行此命令
如果(!cts.Token.IsCancellationRequested)
{
//将作为集合的缓存项重新水化
WriteLine(string.Format(“线程[{0}]执行了工作”,Thread.CurrentThread.ManagedThreadId));
WriteLine(string.Format(“Was最后一个执行线程:{0}.Was{1}”,AtomicCounter==2000?“TRUE”:“FALSE”,AtomicCounter));
WriteLine(string.Format(“QueueUserWorkItem调用{0}”,tN));
}
}
捕获(例外e)
{
Console.WriteLine(“在:\r\n“+e.StackTrace中发生异常”);
}
}
}
public class Program
{
static void Main(string[] args)
{
///////////////////////////////////////////////////////////////////////////////
// Test
//
// Out:
// Thread [852] performed the work
// Was last executing thread: FALSE. Was #897
// QueueUserWorkItem Call 1762
// Thread [854] performed the work
// Was last executing thread: FALSE. Was #1412
// QueueUserWorkItem Call 1391
// Thread [1836] performed the work
// Was last executing thread: TRUE. Was #2000
// QueueUserWorkItem Call 1984
//
///////////////////////////////////////////////////////////////////////////////
Manager mgr = new Manager();
// 2000 rapid updates
for (int i = 0; i < 2000; i++)
{
new Thread(new ParameterizedThreadStart((id) => {
// Thread.Sleep(2000 - (int) id);
Random rand = new Random();
Thread.Sleep(rand.Next(2, 500));
CancellationTokenSource ctSource = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(async (state) => await mgr.PerformTaskAndCancelPreviousTasks(ctSource, (int) id, rand.Next(7, 2500)));
})).Start(i);
};
Task.Delay(15000).Wait(); // Keep ThreadPool alive
}
}
public class Manager
{
private static readonly ConcurrentBag<CancellationTokenSource> CancelTokens = new ConcurrentBag<CancellationTokenSource>();
private static volatile int AtomicCounter = 0;
// Below method gets called like this
// HostingEnvironment.QueueBackgroundWorkItem(async (cancelationToken) => await PerformTaskAndCancelPreviousTasks(cancelationToken));
public async Task PerformTaskAndCancelPreviousTasks(CancellationTokenSource cts, int tN, int delay)
{
try
{
Interlocked.Increment(ref AtomicCounter);
// Cancel all previous tasks
while (!CancelTokens.IsEmpty)
{
CancellationTokenSource previousTaskCancelTokenSource = null;
CancelTokens.TryTake(out previousTaskCancelTokenSource);
if (previousTaskCancelTokenSource != null)
{
previousTaskCancelTokenSource.Cancel();
}
}
CancelTokens.Add(cts); // Add this task's CancellationToken to ConcurrentBag
await Task.Delay(delay); // Simulate network request
// Only the newest task needs to run this, for performance
if (!cts.Token.IsCancellationRequested)
{
// Rehydrate a cache item that is a collection
Console.WriteLine(string.Format("Thread [{0}] performed the work", Thread.CurrentThread.ManagedThreadId));
Console.WriteLine(string.Format("Was last executing thread: {0}. Was #{1}", AtomicCounter == 2000 ? "TRUE" : "FALSE", AtomicCounter));
Console.WriteLine(string.Format("QueueUserWorkItem Call {0}", tN));
}
}
catch (Exception e)
{
Console.WriteLine("Exception occurred in:\r\n" + e.StackTrace);
}
}
}