cub*_*nyc 6 .net c# semaphore cancellation async-await
class Program
{
static IEnumerable<site> list = Enumerable.Range(1, 10).Select(i => new site(i.ToString()));
static void Main(string[] args)
{
startup();
Console.ReadKey();
}
static public void startup()
{
router.cts = new CancellationTokenSource();
foreach (var s in list)
{
update(s);
}
}
async static public void update(site s)
{
try
{
while (true)
{
await s.Refresh();
if (site.count % 4 == 0)
{
Console.WriteLine("Reseting Queue");
router.cts.Cancel();
}
}
}
catch (OperationCanceledException)
{
Console.WriteLine("Canceled");
startup();
}
}
}
class router
{
public static SemaphoreSlim ss = new SemaphoreSlim(1);
public static CancellationTokenSource cts { get; set; }
}
class site
{
public static int count = 0;
public string sitename {get; set;}
public site(string s)
{
sitename = s;
}
async public Task Refresh()
{
await router.ss.WaitAsync(router.cts.Token);
//Console.WriteLine("{0}:: Start Refreshing ", sitename);
await Task.Delay(1000);
Console.WriteLine("{0}:: Done Refreshing ", sitename);
count++;
router.ss.Release();
}
}
Run Code Online (Sandbox Code Playgroud)
我试图模仿一个模式,启动一个无限的while循环,模拟网站的不断更新.我用模数模仿这个.从理论上讲,我希望这可以取消信号量排队的所有任务,并从头开始重新启动队列,但似乎并没有这样做.有人可以评论我的逻辑和模式吗?
现在的输出看起来像这样::
1:: Done Refreshing
2:: Done Refreshing
3:: Done Refreshing
4:: Done Refreshing
Reseting Queue
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
5:: Done Refreshing
1:: Done Refreshing
2:: Done Refreshing
3:: Done Refreshing
Reseting Queue
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
4:: Done Refreshing
5:: Done Refreshing
6:: Done Refreshing
7:: Done Refreshing
Reseting Queue
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
Canceled
8:: Done Refreshing
9:: Done Refreshing
10:: Done Refreshing
1:: Done Refreshing
Reseting Queue
Canceled
Run Code Online (Sandbox Code Playgroud)
所以,我有几条评论,有些是错误,有些只是建议:
update是async void,在事件处理程序之外几乎不应该发生的事情。您无法观察到错误,它会导致无数错误。Task.WhenAllstartup当任何操作被取消时,您正在调用。这意味着当您取消 10 个站点更新中的 5 个时,您将启动 50 个新站点更新。那是不必要的。CancellationToken给SemaphoreSlim.WaitAsynconly 会在等待信号量时观察到取消。任何已经运行的操作都不会停止。这真的是你的意图吗?更好的方法是在更新时检查令牌。这可以通过将令牌传递给Task.Delay操作来模拟。这是我将如何做到的:
class Program
{
static IEnumerable<site> list = Enumerable.Range(1, 10).Select(i => new site(i.ToString()));
static void Main(string[] args)
{
Startup().Wait();
Console.ReadKey();
}
static async Task Startup()
{
while (true)
{
router.cts = new CancellationTokenSource();
await Task.WhenAll(list.Select(s => Update(s)));
}
}
static Task Update(site s)
{
if (site.count % 4 == 0)
{
Console.WriteLine("Reseting Queue");
router.cts.Cancel();
}
else
{
return s.Refresh();
}
}
}
class router
{
public static SemaphoreSlim ss = new SemaphoreSlim(1);
public static CancellationTokenSource cts { get; set; }
}
class site
{
public static int count = 0;
public string sitename {get; set;}
public site(string s)
{
sitename = s;
}
public async Task Refresh()
{
await router.ss.WaitAsync();
try
{
if (router.cts.token.IsCancellationRequested)
{
return;
}
await Task.Delay(500);
if (router.cts.token.IsCancellationRequested)
{
return;
}
await Task.Delay(500);
Console.WriteLine("{0}:: Done Refreshing ", sitename);
count++;
}
finally
{
router.ss.Release();
}
}
}
Run Code Online (Sandbox Code Playgroud)
Task.Delay在我看来,我已将其拆分以使其更类似于您有几个不同操作(例如下载、解析、保存)并且您想在这些步骤之间查询取消标记的真实情况。