Print collection using mutliple tasks Error

Answered Print collection using mutliple tasks Error

  • 09 April 2012 7:55
     
      Memiliki Kode

    Hi guys,

    Recently, I am testing the Task class feature. But having some problems.

    The thing I want to do.

    Print a collection using mutliple tasks.

    Expect:

    All the strings in the collection can be printed out, no duplicate, no one missed.

    Actual:

    The result is random, contains duplicate, and some of them are missed.

    Here is the code:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading.Tasks;
    using System.Threading;
    
    namespace TaskFeatureTest
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                List<int> list = new List<int>();
                for (int i = 0; i < 100; i++)
                {
                    list.Add(i);
                }
                List<List<int>> subLists = list.SplitIntoChunks(5);
    
                int count = subLists.Count;
    
                List<Task> tasks = new List<Task>();
    
                foreach (var subList in subLists)
                {
                    Task t = new Task(() =>
                    {
                        foreach (var a in subList)
                        {
                            Console.WriteLine(a);
                        }
                    });
            
                    t.Start ();
                    tasks.Add(t);
                }
    
                foreach (var t in tasks)
                {
                    t.Wait ();
                }
    
                
            }
        }
    
        public static class Utitlity  
        {
            public static List<List<T>> SplitIntoChunks<T>(this List<T> list, int chunkSize)
            {
                if (chunkSize <= 0)
                {
                    throw new ArgumentException("chunkSize must be greater than 0.");
                }
    
                List<List<T>> retVal = new List<List<T>>();
                int index = 0;
                while (index < list.Count)
                {
                    int count = list.Count - index > chunkSize ? chunkSize : list.Count - index;
                    retVal.Add(list.GetRange(index, count));
    
                    index += chunkSize;
                }
    
                return retVal;
            }
        }
    }
    


    nothing is impossiable for a willing heart

Semua Balasan

  • 09 April 2012 8:18
     
      Memiliki Kode

    Update the middle foreach loop with below one and run the program. Check whether you get desired results.

    foreach (var subList in subLists)
    {
        Task t = new Task(() =>
        {
            foreach (var a in subList)
            {
                Console.WriteLine(a);
            }
        });
        if (tasks.Count == 0)
        {
            t.Start();
        }
        else
        {
            tasks[tasks.Count - 1].ContinueWith(task => t.Start());
        }
        tasks.Add(t);
    }


    Please mark this post as answer if it solved your problem. Happy Programming!

  • 09 April 2012 8:25
     
     
    Sorry, it does not work.

    nothing is impossiable for a willing heart

  • 09 April 2012 8:44
     
     
    Do you get the same results which you were getting before? Because, I have tested the code in my machine, and it works well.

    Please mark this post as answer if it solved your problem. Happy Programming!

  • 09 April 2012 8:58
     
     

    Resut on my side:

    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99
    95
    96
    97
    98
    99

    If you don't mind, would you please share me your binary files. Let me test on my machine.


    nothing is impossiable for a willing heart

  • 09 April 2012 9:21
     
     Jawab Memiliki Kode

    I am sure that you have made something wrong in your SplitIntoChunks function. Anyways, I have shared my exe here (download ConsoleApplication.zip). check it. And below is complete code.

    namespace ConsoleApplication
    {
        class Program
        {
            static Random RandomInt = new Random();
            static void Main(string[] args)
            {
                List<int> list = new List<int>();
                for (int i = 0; i < 100; i++)
                {
                    list.Add(i);
                }
                List<List<int>> subLists = list.SplitIntoChunks(5);
                int count = subLists.Count;
                List<Task> tasks = new List<Task>();
                foreach (var subList in subLists)
                {
                    Task t = new Task(() =>
                    {
                        foreach (var a in subList)
                        {
                            Console.WriteLine(a);
                        }
                    });
                    if (tasks.Count == 0)
                    {
                        t.Start();
                    }
                    else
                    {
                        tasks[tasks.Count - 1].ContinueWith(task => t.Start());
                    }
                    tasks.Add(t);
                }
                foreach (var t in tasks)
                {
                    t.Wait();
                }
            }
        }
        public static class Utitlity
        {
            public static List<List<T>> SplitIntoChunks<T>(this List<T> list, int chunkSize)
            {
                if (chunkSize <= 0)
                {
                    throw new ArgumentException("chunkSize must be greater than 0.");
                }
                List<List<T>> retVal = new List<List<T>>();
                int index = 0;
                while (index < list.Count)
                {
                    int count = list.Count - index > chunkSize ? chunkSize : list.Count - index;
                    retVal.Add(list.GetRange(index, count));
                    index += chunkSize;
                }
                return retVal;
            }
        }   
    }


    Please mark this post as answer if it solved your problem. Happy Programming!

    • Ditandai sebagai Jawaban oleh BruceZhou 09 April 2012 10:35
    •  
  • 09 April 2012 9:34
     
     

    Wierd, I copied your code to my  project, it still gives wrong answer, but the binary file works fine.

    can you share me with your source project?


    nothing is impossiable for a willing heart

  • 09 April 2012 10:35
     
     

    Hi man,

    I acutally get the answer from your binary file. There's tiny difference between the code you post here and the decomplied code in the bin. but actually, it's the tiny thing makes it.

    Thanks.


    nothing is impossiable for a willing heart

  • 09 April 2012 10:58
     
     

    Ahhh.... I am able to reproduce the issue.

    The issue shows  up in Visual Studio 2010 but not in Visual Studio 2011. And I was using VS2011 previously.

    Let me do some R & D and get back to you.

    UPDATE: Yeah.. it is the generated IL code difference. I am not sure why that, but let me dig more into it.


    Please mark this post as answer if it solved your problem. Happy Programming!


  • 09 April 2012 13:17
     
     Jawab Memiliki Kode

    Hi, 

    This is because of, you are building task with delegate still refering subList, whose values are assigned before any of the Task is run.

    So, by the time task starts running subList refers to 95 - 99. so you are seeing 95-99 20 times or some times different numbers, since tasks uses ThreadPool thread so the order is not predicted here.

    How to prove it?

    Test it by slowing down by adding Thread.Sleep(1000), you will see all the values may be order is different like, 

     foreach (IList<int> subList in subLists)
                {
                    Task t = new Task(() =>
                    {
                        foreach (var a in subList) { Console.WriteLine(a); }
                    });
    
                    Thread.Sleep(1000); 
                    if (tasks.Count == 0)
                    {
                        t.Start();
                    }
                    else
                    {
                        tasks[tasks.Count - 1].ContinueWith(task => t.Start());
                    }
                    tasks.Add(t);
                }


    Now, change the code to,

     static void Main(string[] args)
            {
                List<int> list = new List<int>();
                for (int i = 0; i < 100; i++)
                {
                    list.Add(i);
                }
                var subLists = list.SplitIntoChunks(5);
                int count = subLists.Count;
                List<Task> tasks = new List<Task>();
                foreach (IList<int> subList in subLists)
                {
                    Task t = new Task((object o) =>
                    {
                        var subListValues = (List<int>)o;
                        foreach (var a in subListValues) { Console.WriteLine(a); }
                    }, subList);
    
                    if (tasks.Count == 0)
                    {
                        t.Start();
                    }
                    else
                    {
                        tasks[tasks.Count - 1].ContinueWith(task => t.Start());
                    }
                    tasks.Add(t);
                }
                foreach (var t in tasks)
                {
                    t.Wait();
                }
    
                Console.ReadKey();
            }

    So pass the subList object to delegate, this will get solved.

    I do not have 2011 now to comment how it worked with 2011 version...

    I hope this helps you...


    If this post answers your question, please click "Mark As Answer". If this post is helpful please click "Mark as Helpful".



    • Diedit oleh Kris444 09 April 2012 13:18
    • Diedit oleh Kris444 09 April 2012 13:18
    • Ditandai sebagai Jawaban oleh BruceZhou 09 April 2012 13:29
    •  
  • 09 April 2012 13:29
     
     

    kirs444,

    You are correct. Actually vs 2011 may generate code likes you write now.

    Thank you for your accurate analysis.


    nothing is impossiable for a willing heart