簡體   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