2012-02-08 3 views
3

현재 수식 언어에 대한 런타임 (즉, 함수 모음)을 구현 중입니다. 일부 수식에는 컨텍스트를 전달해야하므로 런타임에 액세스해야하는 모든 속성이 포함 된 EvaluationContext라는 클래스를 만들었습니다.ThreadLocal 성능 대 매개 변수 사용

Using ThreadLocal <EvaluationContext> 런타임 환경에서이 컨텍스트를 사용할 수있는 좋은 옵션 인 것 같습니다. 또 다른 옵션은 컨텍스트를 필요한 함수에 매개 변수로 전달하는 것입니다.

ThreadLocal을 사용하는 것을 선호하지만 메서드 매개 변수를 통해 평가 컨텍스트를 전달하는 것과는 달리 성능 저하가 있는지 궁금합니다.

+0

'ThreadLocal <>'에서 '유용성 패널티'에 대해 생각해 보셨습니까? 라이브러리 소비자가 멀티 스레드 된 경우 어떻게해야합니까? –

+0

@Eugen Rieck - 단일 액터 스레드를 통해 모든 호출을 직렬화 할 수 있다고 가정하지만 런타임 자체가 이미 스레드 안전성이있을 수 있으므로 사소한 편의를 위해 상당한 오버 헤드가 추가됩니다. – ChaosPandion

+0

@Eugen Rieck- "유용성 패널티"란 말의 의미를 이해합니다. 내 라이브러리의 소비자는 멀티 스레드이지만, 하나의 공식을 계산하기위한 요청은 하나의 문맥에서 하나의 스레드에서만 발생합니다. 하지만 다른 스레드에서 동일한 런타임 함수를 호출 할 수 있으므로 각 스레드에 대한 컨텍스트를 설정할 필요가 있습니다.런타임 함수는 매개 변수 및이 ThreadLocal 컨텍스트 멤버를 통해 필요한 모든 기능을 제공하므로 스레드로부터 안전합니다. – costa

답변

2

아래 프로그램을 만들었으므로 ThreadLocal 필드보다는 매개 변수를 사용하는 것이 빠릅니다.

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(); 
    } 
    } 
} 
0

성능에 미치는 영향은 없지만이 경우에는 수식 도메인에서 특히 유용 할 수있는 병렬 계산을 수행 할 수 없습니다. 확실히하고 싶지 않다면 ThreadLocal로 갈 수 있습니다.

그렇지 않으면 명시적인 매개 변수없이 계산 (수식)을 통해 상태 (컨텍스트)를 원활하게 전달할 수있는 "상태 모나드" "패턴"을 살펴 보시기 바랍니다.

+0

이것은 재미있어 보입니다. 나는 그것을 볼 것입니다 ... – costa

+0

* * 성능에 영향을 줄 것입니다! 스레드 지역은 무료가 아닙니다. 특수 프로세서 레지스터에 대한 포인터 간접 참조를 사용하여 구현됩니다. – usr

+0

포인터 간접 참조가 왜 느린 지 알 수는 없지만 "특수 프로세서 레지스터"와는 아무 관련이 없습니다. 쓰레드의 스택에 TLS를 저장할 수 있습니다. 요즘 대부분의 Java 구현은 Thread.currentThread()에 매달려있는 사전에 간단히 저장합니다. – tumtumtum

0

ThreadLocal <에 액세스하는 것은 매개 변수에 액세스하는 것보다 시간이 오래 걸리지 만 결국에는 큰 차이가 없을 수도 있습니다. 너는하고있어.

0

나는 ThreadLocal 디자인이 더럽지 만 창조적 인 것으로 생각합니다. 확실히 매개 변수를 사용하는 것이 더 빠를 것입니다 만 성능이 유일한 관심사는 아닙니다. 매개 변수가 훨씬 명확하게 이해됩니다. 나는 당신이 매개 변수와 함께가는 것이 좋습니다.

2

계속 costa의 ;

는 10000000로 N을하려고하면

,

int N = 10000000;

당신이 (107.4 103.4 초 정도) 큰 차이가없는 볼 수 있습니다.

값이 커지면 차이가 줄어 듭니다.

3 초의 느린 속도에 신경 쓰지 않는다면 유용성과 맛의 차이라고 생각합니다.

추신 : 코드에서 int 반환 유형은 long으로 변환되어야합니다.