development

Thread.Sleep이 왜 그렇게 해로운가요?

big-blog 2020. 7. 26. 11:37
반응형

Thread.Sleep이 왜 그렇게 해로운가요?


나는 종종 Thread.Sleep();사용해서는 안된다고 언급했지만 종종 왜 그런지 이해할 수 없습니다. Thread.Sleep();문제를 일으킬 수있는 경우 동일한 결과를 가진 안전한 대안 솔루션이 있습니까?

예.

while(true)
{
    doSomework();
    i++;
    Thread.Sleep(5000);
}

다른 하나는 :

while (true)
{
    string[] images = Directory.GetFiles(@"C:\Dir", "*.png");

    foreach (string image in images)
    {
        this.Invoke(() => this.Enabled = true);
        pictureBox1.Image = new Bitmap(image);
        Thread.Sleep(1000);
    }
}

호출에 대한 문제 Thread.Sleep아르는 간결하게 여기 아주 설명 :

Thread.SleepMTA 스레드에서 테스트 / 디버깅하는 동안 긴 작업을 시뮬레이션합니다. .NET에는 다른 이유가 없습니다.

Thread.Sleep(n)는 최소 n밀리 초 내에 발생할 수있는 타임 슬라이스 (또는 스레드 양자)의 수만큼 현재 스레드를 차단 함을 의미합니다 . 타임 슬라이스의 길이는 Windows의 버전 / 유형 및 프로세서에 따라 다르며 일반적으로 15 ~ 30 밀리 초입니다. 이는 스레드가 n밀리 초 이상 차단되도록 거의 보장됨을 의미합니다 . n밀리 초 후에 스레드가 정확히 다시 깨어날 가능성 은 거의 불가능합니다. 따라서 Thread.Sleep타이밍에 무의미합니다 .

스레드는 제한된 리소스이므로 생성하는 데 약 200,000 회, 파괴하는 데 약 10 만 회가 걸립니다. 기본적으로 스택에 1MB의 가상 메모리를 예약하고 각 컨텍스트 스위치마다 2,000-8,000 사이클을 사용합니다. 이렇게하면 대기 스레드가 낭비가됩니다.

선호되는 솔루션 : WaitHandles

가장 실수는 Thread.Sleepwhile-construct와 함께 사용 하고 있습니다 ( demo and answer , nice blog-entry )

편집 :
내 대답을 향상시키고 싶습니다.

우리는 두 가지 사용 사례가 있습니다.

  1. 계속해야 할 특정 시간 범위 (use 또는 likes)를 알고 있기 때문에 기다리고 있습니다 Thread.Sleep.System.Threading.Timer

  2. 일부 조건이 시간이 바뀌기 때문에 기다리고 있습니다 ... 키워드가 시간입니다 ! 조건 검사가 코드 도메인에 있으면 WaitHandles를 사용해야합니다. 그렇지 않으면 외부 구성 요소가 일종의 후크를 제공해야합니다. 디자인이 좋지 않은 경우!

내 대답은 주로 유스 케이스 2를 다룹니다.


시나리오 1-비동기 작업 완료 대기 : 스레드가 다른 스레드의 작업이 완료되기를 기다리는 시나리오에서 WaitHandle / Auto | ManualResetEvent를 사용해야한다는 데 동의합니다.

시나리오 2-타이밍 while 루프 : 그러나 조잡한 타이밍 메커니즘 (+ Thread.Sleep)은 차단 된 스레드가 언제 "깨어날 *"것인지 정확히 알 필요가없는 99 %의 응용 프로그램에 완벽하게 적합합니다 . 스레드를 생성하는 200k 사이클도 유효하지 않습니다. 어쨌든 타이밍 루프 스레드를 생성해야하고 200k 사이클은 또 다른 큰 숫자입니다 (파일 / 소켓 / db 호출을 여는 사이클 수를 알려주세요)?

while + Thread.Sleep이 작동하면 왜 문제가 복잡합니까? 구문 변호사 만이 실용적입니다 !


코딩 정치 관점 에서이 질문에 대답하고 싶습니다. 누구나 도움이 될 수도 있습니다. 그러나 특히 9-5 명의 기업 프로그래머를 대상으로하는 도구를 다룰 때 문서를 작성하는 사람들은 "무엇을해야할지 정말로 알지 못한다면"하지 말아야한다 "및"절대로 "같은 단어를 사용하는 경향이 있습니다. '하고있는 이유'.

C # 세계에서 가장 좋아하는 두 가지 기능은 "전화 걸지 않음 (this)"또는 "전화 걸지 않음 (GC.Collect ()")이라는 것입니다. 이 두 가지는 많은 블로그와 공식 문서에 강력하게 선언되어 있으며 IMO는 완전한 잘못된 정보입니다. 어떤 수준에서이 잘못된 정보는 대안을 완전히 연구하기 전에 초보자가 이해하지 못하는 일을하지 않도록하는 데 목적이 있지만 동시에 검색 엔진을 통해 실제 정보를 찾기가 어렵습니다. "왜 안돼?"라는 질문에 대한 답을 제시하지 않으면 서 무언가를하지 말라고 말하는 기사를 가리키는 것 같습니다.

Politically, it boils down to what people consider "good design" or "bad design". Official documentation should not be dictating the design of my application. If there's truly a technical reason that you shouldn't call sleep(), then IMO the documentation should state that it is totally okay to call it under specific scenarios, but maybe offer some alternative solutions that are scenario independent or more appropriate for the other scenarios.

Clearly calling "sleep()" is useful in many situations when deadlines are clearly defined in real-world-time terms, however, there are more sophisticated systems for waiting on and signalling threads that should be considered and understood before you start throwing sleep() into your code, and throwing unnecessary sleep() statements in your code is generally considered a beginners' tactic.


It is the 1).spinning and 2).polling loop of your examples that people caution against, not the Thread.Sleep() part. I think Thread.Sleep() is usually added to easily improve code that is spinning or in a polling loop, so it is just associated with "bad" code.

In addition people do stuff like:

while(inWait)Thread.Sleep(5000); 

where the variable inWait is not accessed in a thread-safe manner, which also causes problems.

What programmers want to see is the threads controlled by Events and Signaling and Locking constructs, and when you do that you won't have need for Thread.Sleep(), and the concerns about thread-safe variable access are also eliminated. As an example, could you create an event handler associated with the FileSystemWatcher class and use an event to trigger your 2nd example instead of looping?

As Andreas N. mentioned, read Threading in C#, by Joe Albahari, it is really really good.


Sleep is used in cases where independent program(s) that you have no control over may sometimes use a commonly used resource (say, a file), that your program needs to access when it runs, and when the resource is in use by these other programs your program is blocked from using it. In this case, where you access the resource in your code, you put your access of the resource in a try-catch (to catch the exception when you can't access the resource), and you put this in a while loop. If the resource is free, the sleep never gets called. But if the resource is blocked, then you sleep for an appropriate amount of time, and attempt to access the resource again (this why you're looping). However, bear in mind that you must put some kind of limiter on the loop, so it's not a potentially infinite loop. You can set your limiting condition to be N number of attempts (this is what I usually use), or check the system clock, add a fixed amount of time to get a time limit, and quit attempting access if you hit the time limit.


I agree with many here, but I also think it depends.

Recently I did this code:

private void animate(FlowLayoutPanel element, int start, int end)
{
    bool asc = end > start;
    element.Show();
    while (start != end) {
        start += asc ? 1 : -1;
        element.Height = start;
        Thread.Sleep(1);
    }
    if (!asc)
    {
        element.Hide();
    }
    element.Focus();
}

It was a simple animate-function, and I used Thread.Sleep on it.

My conclusion, if it does the job, use it.


For those of you who hasn't seen one valid argument against use of Thread.Sleep in SCENARIO 2, there really is one - application exit be held up by the while loop (SCENARIO 1/3 is just plain stupid so not worthy of more mentioning)

Many who pretend to be in-the-know, screaming Thread.Sleep is evil failed to mentioned a single valid reason for those of us who demanded a practical reason not to use it - but here it is, thanks to Pete - Thread.Sleep is Evil (can be easily avoided with a timer/handler)

    static void Main(string[] args)
    {
        Thread t = new Thread(new ThreadStart(ThreadFunc));
        t.Start();

        Console.WriteLine("Hit any key to exit.");
        Console.ReadLine();

        Console.WriteLine("App exiting");
        return;
    }

    static void ThreadFunc()
    {
        int i=0;
        try
        {
            while (true)
            {
                Console.WriteLine(Thread.CurrentThread.ThreadState.ToString() + " " + i);

                Thread.Sleep(1000 * 10);
                i++;
            }
        }
        finally
        {
            Console.WriteLine("Exiting while loop");
        }
        return;
    }

참고URL : https://stackoverflow.com/questions/8815895/why-is-thread-sleep-so-harmful

반응형