Monday, 9 January 2023

Parallel Task in .Net 4.0

 Today I will be talking about a new feature of Parallel Programming that was added to .Net 4.0. This article is intended for those familiar with Threads in C#.

 
Considering an example, wherein if one person wants to dig the ground in a 15 mts area then it will take a long time to dig it as required. But if the same work is done by more than 1 person in parallel then the task can be completed faster.
 
faster
 
When I remember having work done single-handed, the following code snippet will answer your question.
  1. Stopwatch watch = new Stopwatch();  
  2.  /*Start Timer*/  
  3.  watch.Start();  
  4.   
  5. /*Task to be performed*/  
  6. for (int index = 0; index < 15; index++)  
  7. {  
  8.       Console.WriteLine("Digging completed for " + index + "mts. area");  
  9.      Thread.Sleep(1000);  
  10. }  
  11. /*Stop Timer*/  
  12. watch.Stop();  
  13. Console.WriteLine("Time required single handed: " + watch.Elapsed.Seconds); 
Output
 
Output
 
Now how to add multiple people working on the same task in parallel?
 
task
 
.Net 4.0 added a new feature of Parallel Programming. This Parallel Programming can be done using Task Parallel Library (TPL). This library is available from the namespace System.Threading.Tasks.
 
The Task Parallel Library (TPL) is the base of the Task-based programming. It consists of:
  • Task class is used to do the unit of work you will code for instead of the previous thread model.
  • Parallel class is a static class that exposes a task-based version of some parallel-nature problems. 
If the same work is to be done with more than 1 worker then what do I need to write?
  1. Stopwatch watch = new Stopwatch();  
  2. watch.Start();  
  3. System.Threading.Tasks.Parallel.For(0, 15, index =>  
  4. {  
  5.     Console.WriteLine("Digging completed for " + index + "mts. area ");  
  6.     Thread.Sleep(1000);                   
  7. }  
  8. );  
  9. watch.Stop();  
  10. Console.WriteLine("Time required time for Parallel digging: " + watch.Elapsed.Seconds); 
Output
 
Result
 
As you can see the difference in timing required by a worker to complete the task single-handedly and by more than 1 respectively. This gives a huge improvement in execution timing when Parallel. For is used.
 
Another alternative is by using Parallel. ForEach that is similar to a foreach loop.
 
Parallel.Invoke
 
Parallel.Invoke
 
Suppose concurrently I want to do many tasks, like digging, cleaning, and so on. So this can be done using the Parallel.Invoke static method. This method will allow me to add various operations and execute them concurrently in parallel.
  1. private void OtherTask()  
  2. {  
  3.     //Some task  
  4. }  
  5.   
  6. private void Digging()  
  7. {  
  8.    //Some task  
  9. }  
  10.   
  11. private void CleanIt()  
  12. {  
  13.     //Some task  
  14. }  
  15.   
  16. public void CallAllTask()  
  17. {  
  18.     Parallel.Invoke(  
  19.       new Action(OtherTask)  
  20.       , new Action(Digging)  
  21.       , new Action(CleanIt));  
The code snippet above will execute all of the list of operations in parallel.
 
ParallelLoopState
 
 
Suppose I want to stop my work after digging at a 10 mts. area. If only one worker was doing this task then it would have been easy. But since many are working in these tasks and each worker is unaware of what the other is doing, I need someone that can interact with each worker and know what is the state of each person's work. In other words before stopping the Parallel Task, I need to maintain a state of the Parallel Tasks executing. This task is handled by the ParallelLoopState class.
 
ParallelLoopState: Enables iterations of Parallel loops to interact with other iterations.
 
There are 2 methods Break () and Stop () to end the task.
 
The differences between the Break and Stop methods are
  • Break ensures that all earlier iterations that started in the loop are executed before exiting the loop.
  • Stop makes no such guarantees; it says that this loop is done and should exit as soon as possible.
  1. Parallel.For(0, 15, (int index, ParallelLoopState loopState) =>  
  2. {  
  3.     if (index == 10)  
  4.     {  
  5.         loopState.Break();  
  6.         //loopState.Stop();  
  7.     }  
  8.     Console.WriteLine("Digging for " + index + "mts. area ");  
  9.     Thread.Sleep(1000);                   
  10. }); 
Output
 
Show Output
 
Using Stop (), as you can see only 11 threads are executed and the task came to a halt.
 
threads
 
Using Break, as you can see one extra loop was executed. This is because as the parallel threads were executing, so it completed the ongoing thread and then stopped.
 
PLINQ
 
LINQ is used for querying through the collection, similarly, PLINQ can be used to query the collection executed with multiple threads. The AsParallel extension method to the collection allows you to query the collection using multiple threads.
  1. bool[] result1 = arr.AsParallel().Select(x => CheckForEven(x)).ToArray(); 
ContinueWith
 
As we know, Task is executed in a different thread. So it is executed asynchronously. And there may be the case that once my task is done, I want to do some other task after completion of the first. This can be done using the ContinueWith extension method.
 
ContinueWtih extension method
  1. Task t2 = null;  
  2. Task t = Task.Factory.StartNew(() =>  
  3. {  
  4.     Console.WriteLine("Digging is in progress");  
  5. });  
  6.   
  7. Console.WriteLine("");  
  8.               
  9. t2 = t.ContinueWith((a) => {  
  10. Console.WriteLine("Clean the area");  
  11. for (int index = 1; index <= 5; index++)  
  12. {  
  13.    Console.WriteLine("Cleaning...." + index);  
  14. }  
  15.  Console.WriteLine("Cleaning done");  
  16.   });  
  17. Task.WaitAll(t, t2);// To ensure both tasks are completed  
  18. Console.Read(); 
In the code snippet above, I am creating a task using the TaskFactory class. Since this task is executed asynchronously, it will continue its execution in a separate Thread. Once this execution is completed, create another Task linked to the first task using the ContinueWith() method.
 
Output
 
ContinueWith method
 

Conclusion

 
Here I conclude this article, saying Parallel programming makes our work easier and faster. I hope you like this article. Please share your comments, whether its good or bad. Sharing is valuable no matter what :)

Sunday, 8 January 2023

What is the use of static variable in C#? When to use it?

 A static variable shares the value of it among all instances of the class.

Example without declaring it static:

public class Variable
{
    public int i = 5;
    public void test()
    {
        i = i + 5;
        Console.WriteLine(i);
    }
}


public class Exercise
{
    static void Main()
    {
        Variable var1 = new Variable();
        var1.test();
        Variable var2 = new Variable();
        var2.test();
        Console.ReadKey();
    }
}

Explanation: If you look at the above example, I just declare the int variable. When I run this code the output will be 10 and 10. Its simple.

Now let's look at the static variable here; I am declaring the variable as a static.

Example with static variable:

public class Variable
{
    public static int i = 5;
    public void test()
    {
        i = i + 5;
        Console.WriteLine(i);
    }
}


public class Exercise
{
    static void Main()
    {
        Variable var1 = new Variable();
        var1.test();
        Variable var2 = new Variable();
        var2.test();
        Console.ReadKey();
    }
}

Now when I run above code, the output will be 10 and 15. So the static variable value is shared among all instances of that class.

Monday, 2 January 2023

Shallow Copy and Deep Copy in C#

 In general, when we try to copy one object to another object, both the objects will share the same memory address. Normally, we use assignment operator, = , to copy the reference, not the object except when there is value type field. This operator will always copy the reference, not the actual object. For Example: Suppose G1 refers to memory address 5000 then G2 will also refer to 5000. So if one will change the value of data stored at address 5000 then both G1 and G2 will show the same data.

Geeks G1 = new Geeks();

// Copy the instance using 
// '=' operator
Geeks G2 = G1;

Shallow Copy: Creating a new object and then copying the value type fields of the current object to the new object. But when the data is reference type, then the only reference is copied but not the referred object itself. Therefore the original and clone refer to the same object. The concept will more clear when you will see the code and the diagram of the Shallow copy.

Note: In the above diagram The Global Rank is value type field so it creates the copy of that and store it in different location but the Name (Desc) is Reference type field so it’s pointing to the old or main memory location.

Example: Here, if you will change value type then it is working on c2 and c1, and not affected but in reference type any change will affect both c1 and c2.

// C# program to illustrate the 
// concept of Shallow Copy
using System;
      
class Example {
      
// Main Method
static void Main(string[] args)
{
      
    Company c1 = new Company(548, "GeeksforGeeks",
                                  "Sandeep Jain");
      
    // Performing Shallow copy                      
    Company c2 = (Company)c1.Shallowcopy(); 
  
    Console.WriteLine("Before Changing: ");
      
    // Before changing the value of
    // c2 GBRank and CompanyName
    Console.WriteLine(c1.GBRank);
    Console.WriteLine(c2.GBRank);
    Console.WriteLine(c2.desc.CompanyName);
    Console.WriteLine(c1.desc.CompanyName);
  
    // changing the value of c2 GBRank
    // and CompanyName
    c2.GBRank = 59;
    c2.desc.CompanyName = "GFG";
  
    Console.WriteLine("\nAfter Changing: ");
      
    // After changing the value of 
    // c2 GBRank and CompanyName
    Console.WriteLine(c1.GBRank);
    Console.WriteLine(c2.GBRank);
    Console.WriteLine(c2.desc.CompanyName);
    Console.WriteLine(c1.desc.CompanyName);
}
}
  
  
class Company 
{
          
    public int GBRank;
    public CompanyDescription desc;
      
    public Company(int gbRank, string c,
                               string o)
    {
        this.GBRank = gbRank;
        desc = new CompanyDescription(c, o);
    }
      
    // method for cloning object
    public object Shallowcopy()
    {
        return this.MemberwiseClone();
    }
      
    // method for cloning object
    public Company DeepCopy()
    {
        Company deepcopyCompany = new Company(this.GBRank,
                            desc.CompanyName, desc.Owner);
        return deepcopyCompany;
    }
}
      
      
class CompanyDescription 
{
      
    public string CompanyName;
    public string Owner;
    public CompanyDescription(string c, string o)
    {
        this.CompanyName = c;
        this.Owner = o;
    }
}
Output:
Before Changing: 
548
548
GeeksforGeeks
GeeksforGeeks

After Changing: 
548
59
GFG
GFG

Deep Copy: It is a process of creating a new object and then copying the fields of the current object to the newly created object to make a complete copy of the internal reference types. If the specified field is a value type, then a bit-by-bit copy of the field will be performed. If the specified field is a reference type, then a new copy of the referred object is performed.

Note:In the above diagram The Global Rank is value type field so it creates the copy of that and store it in different location. The Name(Desc) is Reference type field so in Deep Copy there is a clone of reference type field which also will be stored in a different location.

Example: Here, the field type does not matter whether it is value type or reference type. Deep copy makes a copy of whole data and store it in a different memory location so if we change c2, c1 will not affected vice versa also.

// C# program to demonstrate the
// concept of Deep copy
using System;
  
namespace ShallowVSDeepCopy {
      
class Program {
      
    // Main Method
    static void Main(string[] args)
    {
        Company c1 = new Company(548, "GeeksforGeeks",
                                      "Sandeep Jain");
        // Performing Deep copy                             
        Company c2 = (Company)c1.DeepCopy(); 
  
        Console.WriteLine("Before Changing: ");
           
        // Before changing the value of 
        // c2 GBRank and CompanyName
        Console.WriteLine(c1.GBRank);
        Console.WriteLine(c2.GBRank);
        Console.WriteLine(c2.desc.CompanyName);
        Console.WriteLine(c1.desc.CompanyName);
  
        Console.WriteLine("\nAfter Changing: ");
          
        // changing the value of c2 
        // GBRank and CompanyName
        c2.GBRank = 59;
        c2.desc.CompanyName = "GFG";
  
        // After changing the value of
        // c2 GBRank and CompanyName
        Console.WriteLine(c1.GBRank);
        Console.WriteLine(c2.GBRank);
        Console.WriteLine(c2.desc.CompanyName);
        Console.WriteLine(c1.desc.CompanyName);
    }
}
  
class Company {
      
    public int GBRank;
    public CompanyDescription desc;
  
    public Company(int gbRank, string c, 
                               string o)
    {
        this.GBRank = gbRank;
        desc = new CompanyDescription(c, o);
    }
      
    // method for cloning object
    public object Shallowcopy()
    {
        return this.MemberwiseClone();
    }
      
    // method for cloning object
    public Company DeepCopy()
    {
        Company deepcopyCompany = new Company(this.GBRank,
                           desc.CompanyName, desc.Owner);
                             
        return deepcopyCompany;
    }
}
  
class CompanyDescription {
      
    public string CompanyName;
    public string Owner;
    public CompanyDescription(string c, 
                             string o)
    {
        this.CompanyName = c;
        this.Owner = o;
    }
}
}
Output:
Before Changing: 
548
548
GeeksforGeeks
GeeksforGeeks

After Changing: 
548
59
GFG
GeeksforGeeks