在列表中创建并运行连续任务

时间:2016-06-09 14:29:33

标签: c# .net multithreading task

我有Dictionary< string, Action[] >,我想创建一个任务列表,我已编写此代码来创建将连续执行的任务列表。

var TaskList = new List<Task>();

     foreach (var item in this.Values) {
        if (TaskList.Count == 0) {
           var task = new Task(item[0]);
           var LogAct = task.ContinueWith((t) => item[1](), this.TokenCanc, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
           TaskList.AddRange(new[] { task, LogAct });
        }
        else {
           var task = TaskList[TaskList.Count - 1].ContinueWith((t) => item[0](), this.TokenCanc, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
           var LogAct = task.ContinueWith((t) => item[1](), this.TokenCanc, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
           TaskList.AddRange(new[] { task, LogAct });            
        }
     }
     return TaskList;
  }

现在在此之后,要开始我的连续任务,我打电话:

TaskList[0].Start();

我本来期望执行从1°任务开始到最新任务,但遗憾的是并非如此。

示例:

我将动作添加到我的词典:

 ActionsLog.Add("T1", new Action[] { () => {
    Console.WriteLine("Test1");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest1") });
 ActionsLog.Add("T2", new Action[] { () => {
    Console.WriteLine("Test2");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest2") });
 ActionsLog.Add("T3", new Action[] { () => {
    Console.WriteLine("Test3");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest3") });
 ActionsLog.Add("T4", new Action[] { () => {
    Console.WriteLine("Test4");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest4") });
 ActionsLog.Add("T5", new Action[] { () => {
    Console.WriteLine("Test5");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest5") });
 ActionsLog.Add("T6", new Action[] { () => {
    Console.WriteLine("Test6"); Thread.Sleep(2000); }, () => Console.WriteLine("LogTest6") });

在TaskList [0]之后.Start()我得到输出:

Test1
LogTest6
Test6
LogTest6
Test6
LogTest6
Test6
LogTest6
Test6
LogTest6
Test6
LogTest6

我可能没有采取正确的方法,但我怎样才能解决我的问题?

4 个答案:

答案 0 :(得分:0)

不确定你想做什么,但是

Task.Factory.StartNew(()=>{
    foreach(var action in this.Values.SelectMany(x=>x))
        action();
});

希望它有所帮助。

或者

        var d = new Dictionary<string,Action[]>();
        var origin = new Task(() => { });
        var runner = origin;
        foreach (var action in d.Values.SelectMany(x=>x))
        {
            runner = runner.ContinueWith(prev => action());
        }

        origin.Start();

好的,完成工作样本。只需复制并粘贴。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var ActionsLog = new Dictionary<string, Action[]>();

            ActionsLog.Add("T1", new Action[]
            {
                () =>
                {
                    Console.WriteLine("Test1");
                    Thread.Sleep(2000);
                },
                () => Console.WriteLine("LogTest1")
            });
            ActionsLog.Add("T2", new Action[] { () => {
                    Console.WriteLine("Test2");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest2") });
            ActionsLog.Add("T3", new Action[] { () => {
                    Console.WriteLine("Test3");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest3") });
            ActionsLog.Add("T4", new Action[] { () => {
                    Console.WriteLine("Test4");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest4") });
            ActionsLog.Add("T5", new Action[] { () => {
                    Console.WriteLine("Test5");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest5") });
            ActionsLog.Add("T6", new Action[]
            {
                () =>
                {
                    Console.WriteLine("Test6");
                    Thread.Sleep(2000);
                },
                () => Console.WriteLine("LogTest6")
            });




            var origin = Task.Factory.StartNew(() => { });
            var runner = origin;
            foreach (var action in ActionsLog.Values.SelectMany(x => x))
            {
                runner = runner.ContinueWith(prev => action());
            }

            origin.Wait();


            Console.ReadLine();
        }
    }
}

最后。 在单独的函数中排除执行逻辑

    public static void ExecuteActions(Action[] actions)
    {
        var origin = new Task(() => { });
        var runner = origin;
        foreach (var action in actions)
        {
            runner = runner.ContinueWith(prev => action());
        }

        origin.Start();
        origin.Wait();
    }

并尝试使用不同的Action数组调用它。它应该工作。如果它不适合您,那么您的数据就会出现问题。

答案 1 :(得分:0)

我做的几乎一样,而且有效..

void Main()
{
var actionlog = new Dictionary<string, Action[]>();
actionlog.Add("T1", new Action[] { () => {
                Console.WriteLine("Test1");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest1") });
actionlog.Add("T2", new Action[] { () => {
                Console.WriteLine("Test2");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest2") });
actionlog.Add("T3", new Action[] { () => {
                Console.WriteLine("Test3");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest3") });
actionlog.Add("T4", new Action[] { () => {
                Console.WriteLine("Test4");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest4") });
actionlog.Add("T5", new Action[] { () => {
                Console.WriteLine("Test5");Thread.Sleep(2000);}, () => Console.WriteLine("LogTest5") });
actionlog.Add("T6", new Action[] { () => {
                Console.WriteLine("Test6"); Thread.Sleep(2000); }, () => Console.WriteLine("LogTest6") });

var task = GetTaskChain(actionlog);

task.Start();
}

public Task GetTaskChain(Dictionary<string, Action[]> actionlog)
{
CancellationToken token = new CancellationToken();
var TaskList = new List<Task>();

foreach (var item in actionlog.Values)
{
    if (TaskList.Count == 0)
    {
        var task = new Task(item[0]);
        var LogAct = task.ContinueWith((t) => item[1](), token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
        TaskList.AddRange(new[] { task, LogAct });
    }
    else
    {
        var task = TaskList[TaskList.Count - 1].ContinueWith((t) => item[0](), token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
        var LogAct = task.ContinueWith((t) => item[1](), token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default);
        TaskList.AddRange(new[] { task, LogAct });
    }
}
return TaskList[0];
}  

答案 2 :(得分:0)

它看起来像一个闭包问题。 看看你的编译器 在旧版本foreach循环中,请保留对最后一个代理的引用 因此,例如,此代码将为旧编译器版本打印3 3 3,为新版本打印1 2 3

var numbers = new int[] { 1, 2, 3 };
var actions = new List<Action>();
foreach (var number in numbers)
    actions.Add(() => Console.WriteLine(number));
foreach (var action in actions)
    action();

为避免这种情况,如果使用MS编译器,则编译器的版本应高于4.0.30319.1,如果使用Mono,则编译器的版本应高于2.4.4
您可以找到更多信息herehere

答案 3 :(得分:0)

我有Kote建议我的解决方案。

对于编译器版本v4.0.303191,问题是“ClosureAndForeach”。 代码解决方案是:

var list = new List<Action>();
     foreach (int i in Enumerable.Range(1, 10)) {
        DisplayClass c = new DisplayClass();
        c.i = i;
        list.Add(c.getAct());
     }
     foreach (Action action in list)
        action();

和密封班的代码..

private sealed class DisplayClass {
     public int i;

     public Action getAct() {
        return () => Console.WriteLine(i);
     }
     public void Action() {
        Console.WriteLine(i);
     }
  }

全部谢谢!

相关问题