Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ThreadLocal performance vs using parameters

I am currently implementing a runtime (i.e. a collection of functions) for a formulas language. Some formulas need a context to be passed to them and I created a class called EvaluationContext which contains all properties I need access to at runtime.

Using ThreadLocal<EvaluationContext> seems like a good option to make this context available to the runtime functions. The other option is to pass the context as a parameter to the functions that need it.

I prefer using ThreadLocal but I was wondering if there is any performance penalty as opposed to passing the evaluation context via method parameters.

like image 245
costa Avatar asked Feb 08 '12 00:02

costa


People also ask

Should we use ThreadLocal?

Most common use of thread local is when you have some object that is not thread-safe, but you want to avoid synchronizing access to that object using synchronized keyword/block. Instead, give each thread its own instance of the object to work with.

Is ThreadLocal slow?

Answer 1: In 2009, some JVMs implemented ThreadLocal using an unsynchronised HashMap in the Thread. currentThread() object. This made it extremely fast (though not nearly as fast as using a regular field access, of course), as well as ensuring that the ThreadLocal object got tidied up when the Thread died.

When should ThreadLocal be removed?

You should always call remove because ThreadLocal class puts values from the Thread Class defined by ThreadLocal. Values localValues; This will also cause to hold reference of Thread and associated objects. the value will be set to null and the underlying entry will still be present.

What is ThreadLocal class how and why you should use it?

The ThreadLocal class is used to create thread local variables which can only be read and written by the same thread. For example, if two threads are accessing code having reference to same threadLocal variable then each thread will not see any modification to threadLocal variable done by other thread.


1 Answers

I created the program below and it is faster to use parameters rather than the ThreadLocal field.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TestThreadLocal
{
  internal class Program
  {
    public class EvaluationContext
    {
      public int A { get; set; }
      public int B { get; set; }
    }

    public static class FormulasRunTime
    {
      public static ThreadLocal<EvaluationContext> Context = new ThreadLocal<EvaluationContext>();

      public static int SomeFunction()
      {
        EvaluationContext ctx = Context.Value;
        return ctx.A + ctx.B;
      }

      public static int SomeFunction(EvaluationContext context)
      {
        return context.A + context.B;
      }
    }



    private static void Main(string[] args)
    {

      Stopwatch stopwatch = Stopwatch.StartNew();
      int N = 10000;
      Task<int>[] tasks = new Task<int>[N];
      int sum = 0;
      for (int i = 0; i < N; i++)
      {
        int x = i;
        tasks[i] = Task.Factory.StartNew(() =>
                                                 {
                                                   //Console.WriteLine("Starting {0}, thread {1}", x, Thread.CurrentThread.ManagedThreadId);
                                                   FormulasRunTime.Context.Value = new EvaluationContext {A = 0, B = x};
                                                   return FormulasRunTime.SomeFunction();
                                                 });
        sum += i;
      }
      Task.WaitAll(tasks);

      Console.WriteLine("Using ThreadLocal: It took {0} millisecs and the sum is {1}", stopwatch.ElapsedMilliseconds, tasks.Sum(t => t.Result));
      Console.WriteLine(sum);
      stopwatch = Stopwatch.StartNew();

      for (int i = 0; i < N; i++)
      {
        int x = i;
        tasks[i] = Task.Factory.StartNew(() =>
        {
          return FormulasRunTime.SomeFunction(new EvaluationContext { A = 0, B = x });
        });

      }
      Task.WaitAll(tasks);

      Console.WriteLine("Using parameter: It took {0} millisecs and the sum is {1}", stopwatch.ElapsedMilliseconds, tasks.Sum(t => t.Result));
      Console.ReadKey();
    }
  }
}
like image 99
costa Avatar answered Sep 19 '22 13:09

costa