簡體   English   中英

使用 IEnumerable 的 Do.net 收益率<task<int> > 不工作</task<int>

[英]Dotnet yield with IEnumerable<Task<int>> not working

玩弄 yield 和 Task。

以下簡單示例運行良好。

class Program
{
    private static void Main(string[] args)
    {

        string[] messages = { "First task", "Second task", "Third task", "Fourth task" };

        var taskList = CreateTaskList(messages).ToList();

        taskList.ForEach(task => task.Start());

        Task.WaitAll(taskList.ToArray());

        Console.WriteLine("Main method complete. Press enter to finish.");
        Console.ReadLine();
    }
    static IEnumerable<Task> CreateTaskList(string[] messages)
    {
        foreach (var message in messages)
        {
            yield return new Task(obj => PrintMessage((string)obj!), message);
        }
    }

    static void PrintMessage(object message)
    {
        Console.WriteLine("Message: {0}", message);
    }
}

但是下面沒有。 是否存在一些僵局? 它停留在 Task.WaitAll。 所以我從控制台得到的所有東西都是Before wait all

class SimpleClass
{
    public int Counter { get; set; }
}
class Program
{
    private static void Main(string[] args)
    {
        // create the simple object
        var simpleObject = new SimpleClass();

        var taskList = CreateTaskEnumerable(simpleObject, 10);

        // Start all of the tasks
        foreach (var task in taskList)
            task.Start();

        Console.WriteLine("Before wait all");

        // wait for all of the tasks to complete
        Task.WaitAll(taskList.ToArray());

        Console.WriteLine("After wait all");

        foreach (var task in taskList)
            simpleObject.Counter += task.Result;

        // write out the counter value
        Console.WriteLine("Expected value {0}, Counter value: {1}", 10000, simpleObject.Counter);
        // wait for input before exiting
        Console.WriteLine("Press enter to finish");
        Console.ReadLine();
    }

    private static IEnumerable<Task<int>> CreateTaskEnumerable(SimpleClass simpleObject, int numberOfTasks)
    {
        for (int i = 0; i < numberOfTasks; i++)
        {
            yield return new Task<int>((stateObject) =>
            {
                // get the state object
                var localCounter = (int)stateObject!;

                // enter a loop for 1000 increments
                for (int j = 0; j < 1000; j++)

                    // increment the counters
                    localCounter++;

                return localCounter;
            }, simpleObject.Counter);
        }
    }
}

如果我完全刪除 yield,上面的內容將如下所示,並且有效。 它給出 output 如下。 我也期待上面的相同 output,但那是卡住了。 為什么?

Before wait all
After wait all
Expected value 10000, Counter value: 10000
Press enter to finish

該程序。

class SimpleClass
{
    public int Counter { get; set; }
}
class Program
{
    private static void Main(string[] args)
    {
        // create the bank account instance
        var simpleObject = new SimpleClass();

        // create an list of tasks
        var taskList = new List<Task<int>>();

        for (int i = 0; i < 10; i++)
        {
            // create a new task
            var task = new Task<int>((stateObject) =>
            {
                // get the state object
                var localCounter = (int)stateObject!;

                // enter a loop for 1000 increments
                for (int j = 0; j < 1000; j++)

                    // increment the counters
                    localCounter++;

                return localCounter;
            }, simpleObject.Counter);

            taskList.Add(task);
        }

        // Start all of the tasks
        foreach (var task in taskList)
            task.Start();

        Console.WriteLine("Before wait all");

        // wait for all of the tasks to complete
        Task.WaitAll(taskList.ToArray());

        Console.WriteLine("After wait all");

        foreach (var task in taskList)
            simpleObject.Counter += task.Result;
        
        // write out the counter value
        Console.WriteLine("Expected value {0}, Counter value: {1}", 10000, simpleObject.Counter);
        // wait for input before exiting
        Console.WriteLine("Press enter to finish");
        Console.ReadLine();
    }
}

在第一個示例中,您正在調用CreateTaskList(messages).ToList() ,這會強制CreateTaskList在繼續之前產生所有任務。 在第二個示例中,您沒有調用ToList() ,任務在foreach中產生,然后開始。 問題在Task.WaitAll(taskList.ToArray()); . 它需要IEnumerable並再次產生任務,您正在等待它們完成,但它們尚未開始。 換句話說,每次您在“已產生”的IEnumerable上調用foreachToList()時,它都會運行方法CreateTaskEnumerable並創建新任務。

一種解決方案是調用var taskList = CreateTaskEnumerable(simpleObject, 10).ToList()或者您可以在CreateTaskEnumerable中手動創建列表並返回它。

PS 我建議您閱讀yield return的工作原理,或在https://sharplab.io/中對其進行測試。 它基本上創建了IEnumerable從您的方法中獲取數據。 這意味着每次枚舉IEnumerable時都會執行您的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM