繁体   English   中英

关闭程序前确认所有任务完成

[英]Confirm all tasks are finished before close the program

在我的程序中,启动了很多Task。 此任务可以启动其他任务。 但是当程序关闭时(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
  • 不要管理异步/等待

你有其他策略/想法吗?

编辑:将示例复杂化以生成子工作。

不确定你到底想做什么,但也许像波纹管这样的东西更适合你?

它确保每次任务结束时它都会被列表(锁定的)删除,并且您可以等待所有任务结束。

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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM