C# Async Await, 결국: 비동기 프로그래밍

9718 단어 awaitcsharpasync
나는 C#에서 async/await에 대한 다른 사람들의 설명(예: and)에 대해 불평하는 것으로 알려져 있습니다. 나는 내가 그렇게 많이 알고 있다면 부업에서 싸구려 사진을 찍는 대신 게시물을 작성하지 않는 이유를 들었습니다. 정말 충분히 공평합니다. 문제는 주제를 깊이 이해하려고 하면 주제가 매우 복잡해질 수 있다는 것입니다.

그래서 여기에 그것을 설명하려는 시도가 있습니다. 제가 생각하는 핵심 개념을 간단함과 복잡함의 2단계 난이도로 설명하겠습니다. 나는 또한 여행이 길다는 것을 경고해야합니다 ...



그래서 최대한 분해하겠습니다. 첫 번째 부분에서는 비동기 프로그래밍이 무엇인지 설명하려고 합니다.

비동기 프로그래밍이란 무엇입니까?



간단히: 비동기 프로그래밍이란 무엇입니까?



코드가 기본 프로그램 흐름 외부에서 실행될 수 있도록 하는 프로그래밍입니다. 아래 코드는 기본 프로그램 흐름이 시작되고 끝나는 위치를 보여줍니다.

public static class Example
{
  public static void Main()
  {
    // Here starts the main program flow.
    Console.WriteLine("Do this first");
    Console.WriteLine("Do this second");
    // The main program flow ends once the main returns.
  }
}


따라서 이 프로그램 흐름 외부에서 실행되는 모든 코드는 비동기적으로 실행된다고 합니다.

더 복잡함: 비동기 프로그래밍이란 무엇입니까?




public static void Main()
{
  // Here starts the main program flow.
  Thread worker = new Thread(() =>
  {
    // Sleep the worker thread for 100 milliseconds.
    Thread.Sleep(100);
    Console.WriteLine("Worker Thread: Woke up");
  });

  // Start a worker thread and execute the work 
  // asynchronously.
  worker.Start();

  Thread.Sleep(100);
  Console.WriteLine("Main Thread:   Woke up");

  // Block the main thread until the worker completes.
  worker.Join();

  Console.WriteLine("Main Thread:   Do this last");

  // The main program flow ends once the main returns.
}


그래서 나는 쓰레드의 개념으로 여러분을 때렸을 뿐 설명하지 않았습니다. C#의 스레드는 동일한 애플리케이션 내의 기본 스레드를 비롯한 다른 스레드와 메모리를 공유할 수 있는 경량 프로그램으로 생각할 수 있습니다.

위의 프로그램과 연결된 메인 스레드는 작업자 스레드를 시작하고 100밀리초 동안 휴면 상태가 된 다음 작업자 스레드가 완료될 때까지 기다립니다. (이 경우 작업자 스레드는 기본 스레드가 아닌 또 다른 스레드일 뿐입니다.) 작업자 스레드는 100밀리초 동안 대기한 다음 완료됩니다.

응용 프로그램의 출력은 다음과 같습니다.

Main Thread:   Woke up
Worker Thread: Woke up
Main Thread:   Do this last


Main Thread가 Worker Thread보다 먼저 "Woke up"을 출력할 것으로 예상했습니까?

그렇다면 축하합니다 ... 아마도. 그렇지 않은 경우 비동기 프로그래밍의 기쁨에 오신 것을 환영합니다. 확실하지 않다면 동의합니다. Main Thread가 Worker Thread보다 먼저 출력된다는 명시적인 보장은 없다고 생각합니다. 아마도 Console.WriteLine이 구현되는 방식과 스레드가 런타임에 의해 예약되고 우선 순위가 지정되는 방식에 따라 달라집니다!



작업자 스레드가 메인 스레드보다 먼저 출력할 수 있는 경우에 관심이 있는 경우 다음 코드를 고려하십시오. 그렇지 않으면 건너뛸 수 있습니다.

public static void Main()
{
  int workerRanFirstCount = 0;
  int mainRanFirstCount = 0;
  int totalRuns = 10;

  var runOrder = new ConcurrentQueue<string>();

  var workers = new List<Thread>();

  for (int ii = 0; ii < totalRuns; ++ii)
  {
    workers.Add(new Thread(() =>
    {
      Thread.Sleep(100);
      runOrder.Enqueue("worker");
    }));
  }

  foreach (var worker in workers)
  {
    worker.Start();

    Thread.Sleep(100);
    runOrder.Enqueue("main");

    // Block the main thread until the worker completes.
    worker.Join();

    if (runOrder.First() == "worker") ++workerRanFirstCount;
    if (runOrder.First() == "main") ++mainRanFirstCount;

    runOrder.Clear();
  }

  Console.WriteLine($"Main ran first count = {mainRanFirstCount}; Worker ran first = {workerRanFirstCount}");
}


내 컴퓨터에서 여러 번 실행한 결과는 다음과 같습니다.

Main ran first count = 10; Worker ran first = 0
Main ran first count = 8; Worker ran first = 2
Main ran first count = 6; Worker ran first = 4


결론적으로 스레드 작업의 정확한 인터리빙은 비동기 프로그래밍에서 결정하기 어려울 수 있습니다. 내가 왜 당신에게 이것을 말하고 있습니까? 예측 가능한 비동기 코드를 근본적으로 이해하고 구현하기 위해서는 이 문제를 이해해야 하기 때문입니다.

어느 시점에서 후속 게시물을 작성하려고 시도하겠지만 비동기 프로그래밍에 대한 제 설명에 대해 여러분이 어떻게 생각하는지에 관심이 있습니다. 너무 복잡합니까, 아니면 지금까지 딱 맞습니까?

좋은 웹페이지 즐겨찾기