在任务运行 5 次后启动任务
Starts a Task after a Task runs 5 times
我想在我的任务完成五次后开始一个任务。
这可能以简单的方式实现吗?
我不能用一个简单的计时器来做到这一点,因为我的客户自己在任务中设置时间。当我设置计时器时,应该在第五轮之后开始的任务在错误的时间开始。
我有一个程序,其任务(8 个任务)一个接一个地开始和结束。最后一个任务然后再次开始第一个任务。而且我不知何故需要一个在第五轮结束时计数的计数器。所以最后一个任务必须完成第五次,然后我要包括的这个特定任务应该自动打开,如果完成则开始第一个任务。
这是我的异步任务..它以按钮开始并重复..它只是一个最小化版本。
async void STARTCLICK(CancellationToken token)
{
for (int i = 0; i < 2; i++)
{
try
{
token.ThrowIfCancellationRequested();
await Task.Delay(100, token);
if ()
{
}
}
catch (AggregateException)
{
MessageBox.Show("Expected");
}
catch (ObjectDisposedException)
{
MessageBox.Show("Bug");
}
catch { }
}
Thread.Sleep(2000);
var t2 = Task.Run(() => START(token));
await Task.WhenAny(new[] { t2 });
}
async void START(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
try
{
token.ThrowIfCancellationRequested();
await Task.Delay(100, token);
if ()
{
}
}
catch (AggregateException)
{
Console.WriteLine("Expected");
}
catch (ObjectDisposedException)
{
Console.WriteLine("Bug");
}
catch { }
}
Thread.Sleep(7000);
var t3 = Task.Run(() => MOVE(token));
await Task.WhenAny(new[] { t3 });
}
async void MOVE(CancellationToken token)
{
for (int i = 0; i < 4; i++)
{
try
{
token.ThrowIfCancellationRequested();
await Task.Delay(100, token);
if ()
{
}
}
catch (AggregateException)
{
Console.WriteLine("Expected");
}
catch (ObjectDisposedException)
{
Console.WriteLine("Bug");
}
catch { }
}
var t4 = Task.Run(() => RESTART(token));
await Task.WhenAny(new[] { t4 });
}
async void RESTART(CancellationToken token)
{
for (int i = 0; i < 4; i++)
{
try
{
token.ThrowIfCancellationRequested();
await Task.Delay(100, token);
if ()
{
}
}
catch (AggregateException)
{
Console.WriteLine("Expected");
}
catch (ObjectDisposedException)
{
Console.WriteLine("Bug");
}
catch { }
}
var t4 = Task.Run(() => STARTCLICK(token));
await Task.WhenAny(new[] { t4 });
这样写脚本可行吗? REPAIR 是我每 5 次才需要的任务...我需要在我的任务中取消令牌。因为任务非常大,应该随时停止。
修复是 EXITACCEPT 和 RESTART 之间的任务。
您实现无限递归循环的方式有点粗略。维护它应该是相当困难的。我的建议是删除异步方法之间的 dependencies/interactions,并将以循环方式调用它们的责任委托给“主”异步方法,该方法在 while
循环中顺序调用它们:
async Task InfiniteLoopAsync()
{
long iteration = 0;
while (true)
{
iteration++;
await Method_A();
await Method_B();
await Method_C();
await Method_D();
if (iteration % 5 == 0) await Method_E();
}
}
每个方法都应该有一个 Task
return 类型,而不是 void
:
async Task Method_A()
{
}
终于可以像这样开始无限循环了:
private async void Button1_Click(object sender, EventArgs args)
{
await InfiniteLoopAsync();
}
Click
事件处理程序应该是您唯一具有 async void
签名的方法。
使用最大计数为 5 的 SemaphoreSlim
。这意味着一次最多有 5 个线程可以进入此信号量。一旦所有五个都被消耗掉,执行特殊任务并释放信号量上的 5 个线程。冲洗并重复。
这是一个例子。警告:TaskRepeater
class 错误(例如异常处理)。
using System;
using System.Threading;
using System.Threading.Tasks;
var taskRepeater = new TaskRepeater(async () => await RepeatedTaskAsync(), 5);
await taskRepeater.RunAsync(async () => await RegularTaskAsync("A"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("B"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("C"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("D"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("E"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("F"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("G"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("H"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("I"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("J"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("K"));
static async Task RepeatedTaskAsync()
{
Console.WriteLine("Running repeated task.");
await Task.Delay(500);
}
static async Task RegularTaskAsync(string id)
{
Console.WriteLine($"Running regular task {id}.");
await Task.Delay(50);
}
public class TaskRepeater
{
private readonly int frequency;
private readonly Func<Task> repeatTaskFactory;
private readonly SemaphoreSlim semaphore;
private readonly SemaphoreSlim repeatSemaphore;
public TaskRepeater(Func<Task> repeatTaskFactory, int frequency)
{
this.frequency = frequency;
this.repeatTaskFactory = repeatTaskFactory;
this.semaphore = new SemaphoreSlim(frequency, frequency);
this.repeatSemaphore = new SemaphoreSlim(1, 1);
}
public async Task RunAsync(Func<Task> taskFactory)
{
try
{
await this.semaphore.WaitAsync();
await taskFactory.Invoke();
if (this.semaphore.CurrentCount == 0 && this.repeatSemaphore.CurrentCount != 0)
{
await this.PerformRepeatedTaskAsync();
}
}
catch (Exception)
{
if (this.semaphore.CurrentCount == 0)
{
this.semaphore.Release();
}
if (this.repeatSemaphore.CurrentCount > 0)
{
this.repeatSemaphore.Release();
}
throw;
}
}
private async Task PerformRepeatedTaskAsync()
{
await this.repeatSemaphore.WaitAsync();
if (this.semaphore.CurrentCount > 0)
{
this.repeatSemaphore.Release();
return;
}
await this.repeatTaskFactory.Invoke();
this.semaphore.Release(frequency);
this.repeatSemaphore.Release();
}
}
这输出:
Running regular task A.
Running regular task B.
Running regular task C.
Running regular task D.
Running regular task E.
Running repeated task.
Running regular task F.
Running regular task G.
Running regular task H.
Running regular task I.
Running regular task J.
Running repeated task.
Running regular task K.
我想在我的任务完成五次后开始一个任务。 这可能以简单的方式实现吗? 我不能用一个简单的计时器来做到这一点,因为我的客户自己在任务中设置时间。当我设置计时器时,应该在第五轮之后开始的任务在错误的时间开始。
我有一个程序,其任务(8 个任务)一个接一个地开始和结束。最后一个任务然后再次开始第一个任务。而且我不知何故需要一个在第五轮结束时计数的计数器。所以最后一个任务必须完成第五次,然后我要包括的这个特定任务应该自动打开,如果完成则开始第一个任务。
这是我的异步任务..它以按钮开始并重复..它只是一个最小化版本。
async void STARTCLICK(CancellationToken token)
{
for (int i = 0; i < 2; i++)
{
try
{
token.ThrowIfCancellationRequested();
await Task.Delay(100, token);
if ()
{
}
}
catch (AggregateException)
{
MessageBox.Show("Expected");
}
catch (ObjectDisposedException)
{
MessageBox.Show("Bug");
}
catch { }
}
Thread.Sleep(2000);
var t2 = Task.Run(() => START(token));
await Task.WhenAny(new[] { t2 });
}
async void START(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
try
{
token.ThrowIfCancellationRequested();
await Task.Delay(100, token);
if ()
{
}
}
catch (AggregateException)
{
Console.WriteLine("Expected");
}
catch (ObjectDisposedException)
{
Console.WriteLine("Bug");
}
catch { }
}
Thread.Sleep(7000);
var t3 = Task.Run(() => MOVE(token));
await Task.WhenAny(new[] { t3 });
}
async void MOVE(CancellationToken token)
{
for (int i = 0; i < 4; i++)
{
try
{
token.ThrowIfCancellationRequested();
await Task.Delay(100, token);
if ()
{
}
}
catch (AggregateException)
{
Console.WriteLine("Expected");
}
catch (ObjectDisposedException)
{
Console.WriteLine("Bug");
}
catch { }
}
var t4 = Task.Run(() => RESTART(token));
await Task.WhenAny(new[] { t4 });
}
async void RESTART(CancellationToken token)
{
for (int i = 0; i < 4; i++)
{
try
{
token.ThrowIfCancellationRequested();
await Task.Delay(100, token);
if ()
{
}
}
catch (AggregateException)
{
Console.WriteLine("Expected");
}
catch (ObjectDisposedException)
{
Console.WriteLine("Bug");
}
catch { }
}
var t4 = Task.Run(() => STARTCLICK(token));
await Task.WhenAny(new[] { t4 });
这样写脚本可行吗? REPAIR 是我每 5 次才需要的任务...我需要在我的任务中取消令牌。因为任务非常大,应该随时停止。
修复是 EXITACCEPT 和 RESTART 之间的任务。
您实现无限递归循环的方式有点粗略。维护它应该是相当困难的。我的建议是删除异步方法之间的 dependencies/interactions,并将以循环方式调用它们的责任委托给“主”异步方法,该方法在 while
循环中顺序调用它们:
async Task InfiniteLoopAsync()
{
long iteration = 0;
while (true)
{
iteration++;
await Method_A();
await Method_B();
await Method_C();
await Method_D();
if (iteration % 5 == 0) await Method_E();
}
}
每个方法都应该有一个 Task
return 类型,而不是 void
:
async Task Method_A()
{
}
终于可以像这样开始无限循环了:
private async void Button1_Click(object sender, EventArgs args)
{
await InfiniteLoopAsync();
}
Click
事件处理程序应该是您唯一具有 async void
签名的方法。
使用最大计数为 5 的 SemaphoreSlim
。这意味着一次最多有 5 个线程可以进入此信号量。一旦所有五个都被消耗掉,执行特殊任务并释放信号量上的 5 个线程。冲洗并重复。
这是一个例子。警告:TaskRepeater
class 错误(例如异常处理)。
using System;
using System.Threading;
using System.Threading.Tasks;
var taskRepeater = new TaskRepeater(async () => await RepeatedTaskAsync(), 5);
await taskRepeater.RunAsync(async () => await RegularTaskAsync("A"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("B"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("C"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("D"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("E"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("F"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("G"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("H"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("I"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("J"));
await taskRepeater.RunAsync(async () => await RegularTaskAsync("K"));
static async Task RepeatedTaskAsync()
{
Console.WriteLine("Running repeated task.");
await Task.Delay(500);
}
static async Task RegularTaskAsync(string id)
{
Console.WriteLine($"Running regular task {id}.");
await Task.Delay(50);
}
public class TaskRepeater
{
private readonly int frequency;
private readonly Func<Task> repeatTaskFactory;
private readonly SemaphoreSlim semaphore;
private readonly SemaphoreSlim repeatSemaphore;
public TaskRepeater(Func<Task> repeatTaskFactory, int frequency)
{
this.frequency = frequency;
this.repeatTaskFactory = repeatTaskFactory;
this.semaphore = new SemaphoreSlim(frequency, frequency);
this.repeatSemaphore = new SemaphoreSlim(1, 1);
}
public async Task RunAsync(Func<Task> taskFactory)
{
try
{
await this.semaphore.WaitAsync();
await taskFactory.Invoke();
if (this.semaphore.CurrentCount == 0 && this.repeatSemaphore.CurrentCount != 0)
{
await this.PerformRepeatedTaskAsync();
}
}
catch (Exception)
{
if (this.semaphore.CurrentCount == 0)
{
this.semaphore.Release();
}
if (this.repeatSemaphore.CurrentCount > 0)
{
this.repeatSemaphore.Release();
}
throw;
}
}
private async Task PerformRepeatedTaskAsync()
{
await this.repeatSemaphore.WaitAsync();
if (this.semaphore.CurrentCount > 0)
{
this.repeatSemaphore.Release();
return;
}
await this.repeatTaskFactory.Invoke();
this.semaphore.Release(frequency);
this.repeatSemaphore.Release();
}
}
这输出:
Running regular task A.
Running regular task B.
Running regular task C.
Running regular task D.
Running regular task E.
Running repeated task.
Running regular task F.
Running regular task G.
Running regular task H.
Running regular task I.
Running regular task J.
Running repeated task.
Running regular task K.