-1

My issue, which it seems I couldn't find an answer is that: why if I change the order of calling a method which contains .AsParallel() and one that doesn't contain, or has different options the result is different.

I've put the source code on GitHub so I don't fill all the screen -> https://github.com/moisoiu/asParallel

And some explication regarding how I've tested it so far.

I'm using other classes to generated some random data and from that point on I'm passing the generated and randomized data to ParallelThreading methods and measure the time via StopWatch class and store the results in a dictionary to show at end the response time.

At first I've assumed that the issue with the performance time, it might be because I work on the same reference, so I've created 4 new objects something which is an array so it will have a new reference, but the results we're the same.

At a point I even assumed that maybe (just maybe) the variable from watch might still store the value from previous one, so I've made a new variable for each one

So any ideas?

Just pick a method from Program.cs, and swap it with some other method and there will be almost the same response time but the method that lasted the most will be the one on TOP and the much less one will be on bottom.

Edit: To respect recommendation from comments below. I've attached a part of the source code, In case is needed more, I will update and remove the link from Git above.

Program.cs

 class Program
{
    static void Main(string[] args)
    {
        var parallelThreading = new ParallelThreading();
        long elapsedMs = 0;
        Dictionary<string, long> results = new Dictionary<string, long>();            

        var dataResults = parallelThreading.InitializeDataForParallelData(6500);
        var something = new PersonModel[6500];
        var something1 = new PersonModel[6500];
        var something2 = new PersonModel[6500];
        var something3 = new PersonModel[6500];
        dataResults.CopyTo(something);
        dataResults.CopyTo(something1);
        dataResults.CopyTo(something2);
        dataResults.CopyTo(something3);

        var watch2 = System.Diagnostics.Stopwatch.StartNew();
        parallelThreading.AsParallelAddingParallelization(something1.ToList());
        watch2.Stop();
        elapsedMs = watch2.ElapsedMilliseconds;
        results.Add(nameof(parallelThreading.AsParallelAddingParallelization), elapsedMs);

        var watch = System.Diagnostics.Stopwatch.StartNew();
        parallelThreading.AsParallel(something2.ToList());
        watch.Stop();
        elapsedMs = watch.ElapsedMilliseconds;
        results.Add(nameof(parallelThreading.AsParallel), elapsedMs);

        var watch1 = System.Diagnostics.Stopwatch.StartNew();
        parallelThreading.WithoutAsParallel(something3.ToList());
        watch1.Stop();
        elapsedMs = watch1.ElapsedMilliseconds;
        results.Add(nameof(parallelThreading.WithoutAsParallel), elapsedMs);

        var watch3 = System.Diagnostics.Stopwatch.StartNew();
        parallelThreading.AsParallelAsOrdered(something.ToList());
        watch3.Stop();
        elapsedMs = watch3.ElapsedMilliseconds;
        results.Add(nameof(parallelThreading.AsParallelAsOrdered), elapsedMs);


        foreach (var result in results)
        {
            WriteTime(result.Key, result.Value);
        }

        Console.ReadLine();
    }

    private static void WriteTime(string methodName, long elapsedMiliseconds)
    {
        Console.WriteLine($" {methodName}: Milisecond passed: { elapsedMiliseconds}");
    }
}

ParallelThreading.cs

 public class ParallelThreading
{

    private List<PersonModel> RandomData(int range)
    {
        List<PersonModel> personModels = new List<PersonModel>();
        for (int i = 0; i < range; i++)
        {
            var person = new PersonModel()
            {
                NumberIdentification = i,
                Age = Convert.ToInt32(GenerateString.RandomNumbers(2)),
                DateOfBirth = GenerateString.GenerateDateTime(),
                LastName = GenerateString.RandomString(10),
                Name = GenerateString.RandomString(10),
                City = GenerateString.RandomString(10)
            };
            personModels.Add(person);
        }
        return personModels;
    }

    private List<PersonModel> RandomDataWithSpecificSameData(int range, string city)
    {

        List<PersonModel> personModels = new List<PersonModel>();
        for (int i = 0; i < range; i++)
        {
            var person = new PersonModel();
            if (GenerateString.random.Next(range - 1) % 2 == 0)
            {
                person = new PersonModel()
                {
                    NumberIdentification = i,
                    Age = Convert.ToInt32(GenerateString.RandomNumbers(2)),
                    DateOfBirth = GenerateString.GenerateDateTime(),
                    LastName = GenerateString.RandomString(10),
                    Name = GenerateString.RandomString(10),
                    City = city
                };
            }
            else
            {
                person = new PersonModel()
                {
                    NumberIdentification = i,
                    Age = Convert.ToInt32(GenerateString.RandomNumbers(2)),
                    DateOfBirth = GenerateString.GenerateDateTime(),
                    LastName = GenerateString.RandomString(10),
                    Name = GenerateString.RandomString(10),
                    City = GenerateString.RandomString(10),                        
                };
            }
            personModels.Add(person);
        }
        return personModels;
    }


    #region AsParallelLINQ

    public List<PersonModel> InitializeDataForParallelData(int range)
    {
        return RandomDataWithSpecificSameData(range, "Oradea");
    }

    public void AsParallel(List<PersonModel> data)
    {
        var result = data
            .AsParallel()
            .Where(c => c.City == "Oradea")
            .Select(c => c);
        foreach (var person in result)
        {
            Console.WriteLine($"{person.NumberIdentification} + {person.Name} + {person.City}");
        }
    }

    public void AsParallelAddingParallelization(List<PersonModel> data)
    {
        var result = data
            .AsParallel()
            .WithDegreeOfParallelism(8)
            .WithExecutionMode(ParallelExecutionMode.ForceParallelism)
            .Where(c => c.City == "Oradea")
            .Select(c => c);
        foreach (var person in result)
        {
            Console.WriteLine($"{person.NumberIdentification} + {person.Name} + {person.City}");
        }
    }

    public void AsParallelAsOrdered(List<PersonModel> data)
    {
        var result = data
            .AsParallel()
            .AsOrdered()
            .Where(c => c.City == "Oradea")
            .Select(c => c);
        foreach (var person in result)
        {
            Console.WriteLine($"{person.NumberIdentification} + {person.Name} + {person.City}");
        }
    }

    public void WithoutAsParallel(List<PersonModel> data)
    {
        var result = data.Where(c => c.City == "Oradea").Select(c => c);
        foreach (var person in result)
        {
            Console.WriteLine($"{person.NumberIdentification} + {person.Name} + {person.City}");
        }
    }

    #endregion

}

Example of result with name and time elapsed

Example of result when the method name is swapped

Mircea Mihai
  • 167
  • 1
  • 13
  • The reason is that I didn't want to fill a screen with source code, because it won't help anyone, to connect the dots between a screen of code or another. The results expected as I mentioned in the post above is that, Why if I swap the methods I still get almost the same response time ? The test I've made it in Debug and the version it's the .Net Core version 2.1.402 – Mircea Mihai Sep 03 '18 at 06:43
  • 2
    If you need to benchmark your code you should probably use https://github.com/dotnet/BenchmarkDotNet to avoid the common pitfalls when trying to measure the performance of code. – Oliver Sep 03 '18 at 07:29
  • mjwills I agree, but there was no big difference between Debug or Release. @Magnus What did I expect is that whenever I run a method (ex AsParallelAddingParallelization() ) to get the same elapsed miliseconds. And not a different time if I swap the method (ex. last one with the first one) Oliver Thanks for the suggestion, I will give it a shot. – Mircea Mihai Sep 03 '18 at 07:58
  • Sorry didn't see the links before. I will answer first on the questions you asked on the comment -> Why are the later method calls faster"? Is that correct? Does the behaviour change if you set learn.microsoft.com/en-us/dotnet/api/… to 50? Not quite, I'm trying to find an explication why if I call sequential methods (ex: a,b,c,d) the process it takes from the most to the less. (ex: a = 3 seconds, b = 2 seconds, c = 1 second and d = 0.5 seconds) and if i swap the methods the time remains **almost** the same (ex: d = 3 seconds, b = 2 seconds, c = 1 second and a = 0.5 seconds) – Mircea Mihai Sep 03 '18 at 08:50
  • Yes, but I have a feeling we're missing the point from begin but the response on which method is executed does improve overall. So my question, from the begin when I run the application why the first method takes the most of time and the last the less time ? And If I swap those methods the results are the same (aka top method takes the most, last method takes the less) If i run only one by one (comment the code and only run one) it keeps the average time (ex. 1.5 seconds) – Mircea Mihai Sep 03 '18 at 09:25
  • 1
    I'd suggest having a read of https://stackoverflow.com/questions/19388372/when-doing-performance-testing-why-are-the-initial-iterations-constantly-slower . @Oliver's recommendation will be helpful in reducing the impact of the 'first invocation always slower' effect and thus doing a real performance comparison. – mjwills Sep 03 '18 at 09:26
  • I've read it a couple of times to see if I don't miss something. And I think I've found where the issue might occurred. But still would like to investigate further more if you have any other links beside the one you mentioned above (The-CLR-Thread-Pool-Thread-Injection-Algorithm/) please let me know. What have I tried now, I've duplicate the code from Program.CS (where the 4 methods are called) and I've obtain slight different results (lower times) but still have the issue that If it's the last one called I get better performance (better time) – Mircea Mihai Sep 03 '18 at 09:40

1 Answers1

1

I want to start with many thanks to @mjwills and @Oliver for the help and links provided.

After scratching a bit the surface of BenchmarkDotNet (has a ton of options) and some tweaks to the solution, it seems that (at least) for my case there is no difference between the methods (but that'a a different problem, on how, when and what type of data should AsParallel be used on to obtain performance).

Summary from the comment from the first post: My concern was why the methods called from top to bottom the time lapse it's from longest to shortest even if I swap the methods (ex, the last one from bottom with the first one from top)

So, behind the scenes was because at first time there is a "warm-up" process where involves in caching mechanism for different operations Stackoverflow link to details

So as a solutin to the problem: use BenchmarkDotNet, and don't forget about caching operations (the one mentioned above)

Mircea Mihai
  • 167
  • 1
  • 13