繁体   English   中英

c#在执行之前建立一个任务列表

[英]c# build a list of tasks before executing

我正在尝试在执行任务之前建立一个任务列表。 这是一些示例代码:

    public string Returnastring(string b)
    {
        return b;
    }

    public string Returnanotherstring(string a)
    {
        return a;
    }


    private void btnT_Click(object sender, EventArgs e)
    {
        bool cont = true;

        var Returnastringtask = Task.Factory.StartNew(() => Returnastring("hi"));
        var Returnanotherstringtask = Task.Factory.StartNew(() => Returnanotherstring("bye"));

        if (cont)
        {
            Task.WaitAll(new Task[] { Returnastringtask });
        }
        else
        {
            Task.WaitAll(new Task[] { Returnanotherstringtask });
        }

我知道当这两个任务都运行时,这段代码的行为并不符合我的预期。 我想基本上最初创建任务,然后根据布尔值执行一个或另一个。 我不想在 true 或 false 条件下创建任务,因为我想避免代码复制。 我的意思是,如果 cont 为真,我可能想运行任务 1、2、3、4,但如果 cont 为假,我可能想运行任务 2、3、7、8。

嗯,另一种方法,(我觉得很直接)

        var list = new List<Task>();
        for (var i = 0; i < 10; ++i)
        {
            var i2 = i;
            var t = new Task(() =>
                {
                    Thread.Sleep(100);
                    Console.WriteLine(i2);
                });
            list.Add(t);
            t.Start();
        }

        Task.WaitAll(list.ToArray());

而不是使用Task.Factory.StartNew来创建任务(线索在名称中),而是通过使用new Task(...)与您的 lambdas 来创建它们,然后只需在您的条件中使用taskName.Start()想开始他们。

您可以根据一个标志创建一个Action数组,然后使用Parallel.Invoke()运行该数组中的所有操作并等待它们完成。

如果需要,您可以将 lambda 用于操作,这将允许您将它们的返回值分配给局部变量。

这是一个完整的可编译示例。 尝试使用getFlag()返回true并再次返回false

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    sealed class Program
    {
        void run()
        {
            bool flag = getFlag();
            var results = new string[5];
            Action[] actions;

            if (flag)
            {
                actions = new Action[]
                {
                    () => results[0] = function("f1"),
                    () => results[1] = function("f2"),
                    () => results[2] = function("f3")
                };
            }
            else
            {
                actions = new Action[]
                {
                    () => results[3] = function("f4"),
                    () => results[4] = function("f5")
                };
            }

            Parallel.Invoke(actions); // No tasks are run until you call this.

            for (int i = 0; i < results.Length; ++i)
                Console.WriteLine("Result {0} = {1}", i, results[i]);
        }

        private bool getFlag()
        {
            return true; // Also try with this returning false.
        }

        string function(string param)
        {
            Thread.Sleep(100); // Simulate work.
            return param;
        }

        static void Main(string[] args)
        {
            new Program().run();
        }
    }
}

Task.Factory.StartNew 将实际开始您的任务。 您想设置任务,然后根据某些逻辑运行它们。

你可以在任何地方构建你的任务,但你应该在逻辑之后开始它们。 此示例在逻辑之后构建它们。

也许你可以这样运行它:

If(A)
{
     doA();
}
Else
{
     doB();
}

然后在您调用的函数内开始您的任务,例如:

public void doA()
{
     for (int i = 0; i < NumberOfTasks; i++)
     {
          tasks[i] = Task.Factory.StartNew(() =>
          {
               try
               {
                    //enter tasks here 
                    // i.e. task 1, 2, 3, 4
               }
          }
     }, token);

     Task.WaitAll(tasks);    
}

我所做的一切都是基于 Samuel 所做的,除了我有一个递归事件处理程序需要完成它正在做的事情,因为它的子事件依赖于它已经完成(用于在 ASP.NET 应用程序的动态 UI 中嵌套控件)。 所以如果你想做同样的事情,除了你正在处理一个事件,而且你不是多线程,因为你需要同步处理多个任务,而不是在调用堆栈上乱搞。

    private static Queue<Task> _dqEvents = new Queue<Task>();
    private static bool _handlingDqEvent = false;

    protected void HandleDynamicQuestion(int SourceQuestionId, int QuestionId)
    {
        //create a task so that we can handle our events in sequential order, since additional events may fire before this task is completed, and depend upon the completion of prior events
        Task task = new Task(() => DoDynamicQuestion(SourceQuestionId, QuestionId));
        lock(_dqEvents) _dqEvents.Enqueue(task);
        if (!_handlingDqEvent)
        {
            try
            {
                //lockout any other calls in the stack from hitting this chunk of code
                lock (_dqEvents) _handlingDqEvent = true;

                //now run all events in the queue, including any added deeper in the call stack that were added to this queue before we finished this iteration of the loop
                while (_dqEvents.Any())
                {
                    Task qt;
                    lock (_dqEvents) qt = _dqEvents.Dequeue();
                    qt.RunSynchronously();
                }
            }
            finally
            {
                lock (_dqEvents) _handlingDqEvent = false;
            }
        }
        else
            //We exit the method if we're already handling an event, as the addition of new tasks to the static queue will be handled synchronously.
            //Basically, this lets us escape the call stack without processing the event until we're ready, since the handling of the grandchild event 
            //is dependent upon its parent completing.
            return;
    }

    private void DoDynamicQuestion(int SourceQuestionId, int QuestionId)
    {
        //does some stuff that has no dependency on synchronicity

        //does some stuff that may eventually raise the event above

        //does some other stuff that has to complete before events it triggers can process correctly
    }

暂无
暂无

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

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