在关闭程序之前确认所有任务都已完成
Confirm all tasks are finished before close the program
在我的程序中,启动了很多任务。此任务可以启动其他任务。但是当程序关闭时(Main 方法结束),所有 运行 任务都在工作中停止。
我需要在程序关闭时,关闭进程等待所有任务。为此,我注册了所有启动的任务,并在最后一条指令中等待所有注册任务:
public static class HostedTask
{
private readonly static ConcurrentQueue<Task> _tasks = new ConcurrentQueue<Task>();
public static void Run(Action action)
{
var task = Task.Factory.StartNew(action, TaskCreationOptions.LongRunning);
_tasks.Enqueue(task);
}
public static void Wait()
{
while (_tasks.Any())
{
if (_tasks.TryDequeue(out Task task))
{
task.Wait();
}
}
}
}
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
for (int i = 0; i < 100; i+= 10)
{
LongBackgroundWork(i);
}
HostedTask.Wait();
}
static void LongBackgroundWork(int id)
{
HostedTask.Run(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(10));
Console.WriteLine(id + " End");
for (var i = id + 1; i < id + 10; i++)
ChildWork(i);
});
}
static void ChildWork(int id)
{
HostedTask.Run(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine(id + " End");
});
}
这个策略有一些问题:
- 集合永远不会被清理,它可以无限增长
- 需要替换所有任务声明
- 不管理 ContinueWith
- 不管理async/await
你还有其他的strategy/idea吗?
编辑:将示例复杂化以生成子工作。
不确定你到底想做什么,但也许像下面这样的东西更适合你?
它确保每次任务结束时它都会被列表(锁定的)删除,并且您可以等待所有任务结束。
public static class HostedTask
{
private readonly static List<Task> _tasks = new List<Task>();
private static Object taskLocker = new object();
public static async Task Run(Action action)
{
var task = Task.Factory.StartNew(action, TaskCreationOptions.LongRunning);
lock (taskLocker)
_tasks.Add(task);
await task;
lock (taskLocker)
_tasks.Remove(task);
}
public static void Wait()
{
IEnumerable<Task> anys;
do
{
lock (taskLocker)
{
anys = _tasks.Where(t => !t.IsCompleted);
}
if ((anys != null) && (anys.Count() > 0))
Task.WhenAll(anys).Wait();
else return;
} while (true);
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
for (int i = 0; i < 100; i++)
{
LongBackgroundWork(i);
}
ShortBackgroundWork(-1);
HostedTask.Wait();
}
static Task LongBackgroundWork(int id)
{
return HostedTask.Run(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(10));
Console.WriteLine(id + " End");
});
}
static Task ShortBackgroundWork(int id)
{
return HostedTask.Run(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(1));
Console.WriteLine(id + " End");
});
}
}
为了好玩,前台任务计划程序。此调度程序将在新的前台线程上执行所有任务:
public class ForegroundTaskScheduler : TaskScheduler
{
protected override IEnumerable<Task> GetScheduledTasks()
{
return Enumerable.Empty<Task>();
}
protected override void QueueTask(Task task)
{
new Thread(() => base.TryExecuteTask(task)).Start();
}
protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return false; //No inline
}
}
public static class ForegroudTask
{
public static TaskScheduler Scheduler { get; }
public static TaskFactory Factory { get; }
static ForegroudTask()
{
Scheduler = new ForegroundTaskScheduler();
Factory = new TaskFactory(Scheduler);
}
}
使用:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
for (int i = 0; i < 100; i += 10)
{
LongBackgroundWork(i);
}
}
static void LongBackgroundWork(int id)
{
ForegroudTask.Factory.StartNew(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine(id + " End");
}, TaskCreationOptions.LongRunning).ContinueWith(t =>
{
for (var i = id + 1; i < id + 10; i++)
ChildWork(i);
}, ForegroudTask.Scheduler);
}
static void ChildWork(int id)
{
ForegroudTask.Factory.StartNew(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(3));
Console.WriteLine(id + " End");
}, TaskCreationOptions.LongRunning);
}
}
只是这不适用于 async/await。
在我的程序中,启动了很多任务。此任务可以启动其他任务。但是当程序关闭时(Main 方法结束),所有 运行 任务都在工作中停止。
我需要在程序关闭时,关闭进程等待所有任务。为此,我注册了所有启动的任务,并在最后一条指令中等待所有注册任务:
public static class HostedTask
{
private readonly static ConcurrentQueue<Task> _tasks = new ConcurrentQueue<Task>();
public static void Run(Action action)
{
var task = Task.Factory.StartNew(action, TaskCreationOptions.LongRunning);
_tasks.Enqueue(task);
}
public static void Wait()
{
while (_tasks.Any())
{
if (_tasks.TryDequeue(out Task task))
{
task.Wait();
}
}
}
}
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
for (int i = 0; i < 100; i+= 10)
{
LongBackgroundWork(i);
}
HostedTask.Wait();
}
static void LongBackgroundWork(int id)
{
HostedTask.Run(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(10));
Console.WriteLine(id + " End");
for (var i = id + 1; i < id + 10; i++)
ChildWork(i);
});
}
static void ChildWork(int id)
{
HostedTask.Run(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine(id + " End");
});
}
这个策略有一些问题:
- 集合永远不会被清理,它可以无限增长
- 需要替换所有任务声明
- 不管理 ContinueWith
- 不管理async/await
你还有其他的strategy/idea吗?
编辑:将示例复杂化以生成子工作。
不确定你到底想做什么,但也许像下面这样的东西更适合你?
它确保每次任务结束时它都会被列表(锁定的)删除,并且您可以等待所有任务结束。
public static class HostedTask
{
private readonly static List<Task> _tasks = new List<Task>();
private static Object taskLocker = new object();
public static async Task Run(Action action)
{
var task = Task.Factory.StartNew(action, TaskCreationOptions.LongRunning);
lock (taskLocker)
_tasks.Add(task);
await task;
lock (taskLocker)
_tasks.Remove(task);
}
public static void Wait()
{
IEnumerable<Task> anys;
do
{
lock (taskLocker)
{
anys = _tasks.Where(t => !t.IsCompleted);
}
if ((anys != null) && (anys.Count() > 0))
Task.WhenAll(anys).Wait();
else return;
} while (true);
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
for (int i = 0; i < 100; i++)
{
LongBackgroundWork(i);
}
ShortBackgroundWork(-1);
HostedTask.Wait();
}
static Task LongBackgroundWork(int id)
{
return HostedTask.Run(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(10));
Console.WriteLine(id + " End");
});
}
static Task ShortBackgroundWork(int id)
{
return HostedTask.Run(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(1));
Console.WriteLine(id + " End");
});
}
}
为了好玩,前台任务计划程序。此调度程序将在新的前台线程上执行所有任务:
public class ForegroundTaskScheduler : TaskScheduler
{
protected override IEnumerable<Task> GetScheduledTasks()
{
return Enumerable.Empty<Task>();
}
protected override void QueueTask(Task task)
{
new Thread(() => base.TryExecuteTask(task)).Start();
}
protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return false; //No inline
}
}
public static class ForegroudTask
{
public static TaskScheduler Scheduler { get; }
public static TaskFactory Factory { get; }
static ForegroudTask()
{
Scheduler = new ForegroundTaskScheduler();
Factory = new TaskFactory(Scheduler);
}
}
使用:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
for (int i = 0; i < 100; i += 10)
{
LongBackgroundWork(i);
}
}
static void LongBackgroundWork(int id)
{
ForegroudTask.Factory.StartNew(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine(id + " End");
}, TaskCreationOptions.LongRunning).ContinueWith(t =>
{
for (var i = id + 1; i < id + 10; i++)
ChildWork(i);
}, ForegroudTask.Scheduler);
}
static void ChildWork(int id)
{
ForegroudTask.Factory.StartNew(() =>
{
Console.WriteLine(id + " Begin");
Thread.Sleep(TimeSpan.FromSeconds(3));
Console.WriteLine(id + " End");
}, TaskCreationOptions.LongRunning);
}
}
只是这不适用于 async/await。