TLS
이번에 알아 볼 TLS는 우리가 어마어마한 작업을 한다 했을 때 우리의 모든 쓰레드들이 힙영역 전역변수 영역에 다 달라붙어서 작업을 하면 효율이 안좋을 것이다.
그러므로 각 쓰레드들마다 가지고 있는 고유의 작업 공간이라 생각하면 된다.
그래서 작업할 것들을 각자 한 움큼씩 가져와서 TLS에서 작업 한다 생각하면 된다.
일단은, 그냥 TLS를 사용하지않았을 때는 어떨지 알아보면
class Program
{
//static ThreadLocal<string> ThreadName = new ThreadLocal<string>();
static string ThreadName;
static void WhoAmI()
{
//다른 쓰레드들한테는 영향을 안주고 나의 영역에서만
ThreadName = $"My Name is {Thread.CurrentThread.ManagedThreadId}";
Thread.Sleep(1000);
Console.WriteLine(ThreadName);
}
static void Main(string[] args)
{
Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);
}
}
결과 값:
이렇게 같은 쓰레드가 사용되고 있다.
class Program
{
static ThreadLocal<string> ThreadName = new ThreadLocal<string>();
static void WhoAmI()
{
//다른 쓰레드들한테는 영향을 안주고 나의 영역에서만
ThreadName.Value = $"My Name is {Thread.CurrentThread.ManagedThreadId}";
Thread.Sleep(1000);
Console.WriteLine(ThreadName.Value);
}
static void Main(string[] args)
{
ThreadPool.SetMinThreads(1,1);
ThreadPool.SetMaxThreads(3,3);
Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);
}
}
우리가 쓰고자하는 변수에 ThreadLocal을 sealing해주면 된다.
결과 값:
단점이라고 하면, 이미 같은 ThreadId로 한번 실행을 한 상태라서 자신의 Name을 가지고있으면 굳이 ThreadName.Value = $"My Name is {Thread.CurrentThread.ManagedThreadId}"이 부분을 다시 실행 안해도 되는데 계속 실행하는 문제가 있다.
이게 마음에 안들면,
ThreadLocal을 sealing할때 인자를 추가 할 수 있는데
//static ThreadLocal<string> ThreadName = new ThreadLocal<string>(Func<string> valueFactory) 인자 사용
//Func타입이니 람다식으로 간단히 만들어서 테스트
static ThreadLocal<string> ThreadName = new ThreadLocal<string>(() => {return $"My Name is {Thread.CurrentThread.ManagedThreadId}";});
이렇게 선언하면 쓰레드가 새로 실행될때마다 ThreadName을 만들어주는게 아니라 ThreadName의 Value가 세팅이 안됐으면 Value에다가 값을 넣어주게 된다.
그래서,
class Program
{
static ThreadLocal<string> ThreadName = new ThreadLocal<string>(() => {return $"My Name is {Thread.CurrentThread.ManagedThreadId}";});
static void WhoAmI()
{
//이미 만들어져있으면 True로 반환해줌
bool repeat = ThreadName.IsValueCreated;
if(repeat)
Console.WriteLine(ThreadName.Value + "(repeat)");
else
Console.WriteLine(ThreadName.Value);
}
static void Main(string[] args)
{
ThreadPool.SetMinThreads(1, 1);
ThreadPool.SetMaxThreads(3, 3);
Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);
//ThreadName을 삭제하고싶으면
ThreadName.Dispose();
}
}
결과 값 :