PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Monday, October 24, 2022

[FIXED] Why is accessing variables outside of the current thread slow?

 October 24, 2022     asynchronous, c#, concurrency, multithreading     No comments   

Issue

I have the following code with two methods:

using System.Diagnostics;

internal class Program
{
    public static double SeqArraySum(double[] x)
    {
        var watch = new Stopwatch();
        watch.Start();
        double sum1 = 0;
        double sum2 = 0;

        for (int i = 0; i < x.Length / 2; i++)
            sum1 += x[i];

        for (int i = x.Length / 2; i < x.Length; i++)
            sum2 += x[i];

        double sum = sum1 + sum2;
        watch.Stop();
        Console.WriteLine($"Seq Milliseconds: {watch.ElapsedMilliseconds}, sum:{sum}");
        return sum;
    }

    public static double ParArraySum(double[] x)
    {
        var watch = new Stopwatch();
        watch.Start();
        double sum1 = 0;
        double sum2 = 0;

        var t1 = new Thread(() =>
        {
            for (int i = 0; i < x.Length / 2; i++)
                sum1 += x[i];
        });
        t1.Start();

        for (int i = x.Length / 2; i < x.Length; i++)
            sum2 += x[i];

        t1.Join();
        double sum = sum1 + sum2;
        watch.Stop();
        Console.WriteLine($"Par Milliseconds: {watch.ElapsedMilliseconds}, sum:{sum}");
        return sum;
    }

    static void Main()
    {
        var arr = new double[100000000];
        for (int i = 0; i < arr.Length; i++)
            arr[i] = i / 100000000000d;

        for(int i = 1; i <= 5; i++)
        {
            Console.WriteLine($"Attempt {i}");
            var resultSeq = SeqArraySum(arr);
            var resultPar = ParArraySum(arr);
        }
    }
}

If I run this program, I get the following results (.NET Core 6.0, Debugging Mode):

Attempt 1
Seq Milliseconds: 226, sum:49999,999499999976
Par Milliseconds: 448, sum:49999,999499999976
Attempt 2
Seq Milliseconds: 194, sum:49999,999499999976
Par Milliseconds: 409, sum:49999,999499999976
Attempt 3
Seq Milliseconds: 194, sum:49999,999499999976
Par Milliseconds: 463, sum:49999,999499999976
Attempt 4
Seq Milliseconds: 195, sum:49999,999499999976
Par Milliseconds: 460, sum:49999,999499999976
Attempt 5
Seq Milliseconds: 192, sum:49999,999499999976
Par Milliseconds: 457, sum:49999,999499999976

I would expect ParArraySum to run faster, but it isn't happening. But if replace

        var t1 = new Thread(() =>
        {
            for (int i = 0; i < x.Length / 2; i++)
                sum1 += x[i];
        });

with this:

        var t1 = new Thread(() =>
        {
            var tempSum = 0d;
            for (int i = 0; i < x.Length / 2; i++)
                tempSum += x[i];
            sum1 = tempSum;
        });

I get the expected speedup.

Attempt 1
Seq Milliseconds: 217, sum:49999,999499999976
Par Milliseconds: 130, sum:49999,999499999976
Attempt 2
Seq Milliseconds: 241, sum:49999,999499999976
Par Milliseconds: 118, sum:49999,999499999976
Attempt 3
Seq Milliseconds: 199, sum:49999,999499999976
Par Milliseconds: 115, sum:49999,999499999976
Attempt 4
Seq Milliseconds: 191, sum:49999,999499999976
Par Milliseconds: 115, sum:49999,999499999976
Attempt 5
Seq Milliseconds: 192, sum:49999,999499999976
Par Milliseconds: 115, sum:49999,999499999976

Why is my original code so much slower? Is it possible to repeatedly access sum1 without the slowdown?


Solution

By doing this:

double sum1 = 0;
var t1 = new Thread(() =>
{
    for (int i = 0; i < x.Length / 2; i++)
        sum1 += x[i];
});

You capture sum1 local variable in a closure. To make it work, compiler has to rewrite the code so that sum1 is no longer a regular local variable but instead is a field of compiler generated class, and instance of that class is then passed to the closure (the code which another thread runs).

This is important for perfomance in this case, because accessing "regular" local variable, stored on stack, is much more efficient in case of summing large array, and compiler can use various optimizations. Accessing a field of some instance over and over again is less efficient.

In this case:

var t1 = new Thread(() =>
{
    var tempSum = 0d;
    for (int i = 0; i < x.Length / 2; i++)
        tempSum += x[i];
    sum1 = tempSum;
});

You create local variable inside the method you pass to new thread, so it will be "regular" local variable, and repeated access to it is efficient. You then only access captured variable sum1 only once at the end of the loop, which does not negatively affect perfomance.



Answered By - Evk
Answer Checked By - Timothy Miller (PHPFixing Admin)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

1,210,846

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © 2025 PHPFixing