5

MSDN에 따르면,asyncawait새 스레드를 만들지 마라.

그만큼asyncawait키워드는 추가 스레드를 작성하지 않습니다.

이를 염두에두고 몇 가지 간단한 프로그램의 제어 흐름을 이해하는 데 어려움을 겪고 있습니다. 나의 완전한 예가 아래에있다. 참고로데이터 흐름 라이브러리NuGet에서 설치할 수 있습니다.

using System;
using System.Threading.Tasks.Dataflow;

namespace TaskSandbox
{
    class Program
    {
        static void Main(string[] args)
        {
            BufferBlock<int> bufferBlock = new BufferBlock<int>();

            Consume(bufferBlock);
            Produce(bufferBlock);

            Console.ReadLine();
        }

        static bool touched;
        static void Produce(ITargetBlock<int> target)
        {
            for (int i = 0; i < 5; i++)
            {
                Console.Error.WriteLine("Producing " + i);
                target.Post(i);
                Console.Error.WriteLine("Performing intensive computation");
                touched = false;
                for (int j = 0; j < 100000000; j++)
                    ;
                Console.Error.WriteLine("Finished intensive computation. Touched: " + touched);
            }

            target.Complete();
        }

        static async void Consume(ISourceBlock<int> source)
        {
            while (await source.OutputAvailableAsync())
            {
                touched = true;
                int received = source.Receive();
                Console.Error.WriteLine("Received " + received);
            }
        }
    }
}

산출:

Producing 0
Performing intensive computation
Received 0
Finished intensive computation. Touched: True
Producing 1
Performing intensive computation
Received 1
Finished intensive computation. Touched: True
Producing 2
Performing intensive computation
Received 2
Finished intensive computation. Touched: False
Producing 3
Performing intensive computation
Received 3
Finished intensive computation. Touched: False
Producing 4
Performing intensive computation
Received 4
Finished intensive computation. Touched: True

이것은Consume는 통제가 주어지며for루프가 실행 중입니다.OutputAvailableAsync작업 완료 :

for (int j = 0; j < 100000000; j++)
    ;

이것은 스레드 모델에서 놀랄 일이 아닙니다. 그러나 추가 스레드가 포함되어 있지 않으면 어떻게 할 수 있습니까?Produce중간에 수익률 통제for고리?


  • @ I4V : 그 질문에 대한 대답은 "모든 블로킹 동작이 비동기 / 대기 모델을 사용하여 명시 적으로 제어를 내리는 것이 필요하다"는 것을 나타낸다. 하지만 내 질문에, 제어가에서 전달ProduceConsume없이Produce명시 적으로 통제를 내린다. 그것이 내가 혼란스러워하는 부분입니다. - Matthew
  • @Matthew 이것은 콘솔 응용 프로그램이므로 아무 것도 없습니다.SynchronizationContext, 즉 모든 콜백이await전화가왔다SynchronizationContext.Default, 이는 스레드 풀이므로 기술적으로 실제로이 프로그램을 실행하는 동안 실제로 두 개의 스레드가 실행됩니다. 추가 스레드를 만들지 않으려면 사용자 정의 동기화 컨텍스트를 만들어 설정해야합니다. 그렇게했다면Recieved전화를 걸었 기 때문에 모든 제작이 구체적으로 완료 될 때까지 전화를 걸지 않았습니다.아니생산하는 동안 통제를 굴복. - Servy
  • @Servy : 여러 스레드가 관련된 경우 MSDN에서 " 특히 "이 방법은 IO 작업에 BackgroundWorker보다 우수합니다. 경쟁 조건에 대한주의를 기울여야하기 때문입니다." 단순한 경쟁 조건을 추가하기 위해 예제를 편집했습니다. - Matthew
  • @ 매튜 사용await해당 없음필연적으로스레드 생성이 필요합니다. 스레드를 만들지 않는 방법으로 사용할 수 있습니다. 당신은 그렇게하지 않았을 것입니다. 또한 콜백을 실행하기 위해 스레드 풀 스레드를 사용합니다. 해당 스레드 풀 스레드가 아닙니다.블로킹할 일이 없으면 아무 것도하지 않고 수영장으로 다시 풀어줍니다. 다른 요청을 처리 할 수 있습니다. 이는 중요한 것은 100 개의 스레드 풀 스레드가 거기에 앉아있어 IO가 완료 될 때까지 기다리지 않아야한다는 것을 의미하기 때문입니다. - Servy
  • @ 매튜 찾을 수 있습니다나의async/await소개도움이됩니다. 나는 하나의 게시물에 기초 (모든 관련 세부 사항 포함)를 다루려고했다. - Stephen Cleary

2 답변


2

추가적인 스레드가 없다면 어떻게 for 루프의 중간에서 yield 컨트롤을 생성 할 수 있습니까?

누가 추가 스레드가 필요 없다고 했습니까? 네가 진술 한 사실은 :

async 및 await 키워드는 추가 스레드를 만들지 않습니다.

어느 것이 진실입니다. 프로그램에 조각이 포함되어 있습니다.

target.Post(i);

await source.OutputAvailableAsync())

제 추측으로는target.Post(i)또는source.OutputAvailableAsync()스레드를 만들었습니다. 그만큼await스레드를 생성하지 않습니다. 모든await그렇다.메서드의 나머지를 호출에 의해 반환 된 작업의 연속으로 할당 한 다음 호출자에게 제어를 반환합니다.. 이 작업이 작업을 수행하기 위해 스레드를 생성하면 비즈니스입니다.

await다른 제어 흐름 일뿐입니다. 그럼에도 불구하고 제어 흐름은 매우 복잡한 제어 흐름입니다. 쓰래드 생성을위한 통사론적인 설탕이 아닙니다. 그것은 작업에 연속을 할당하기위한 구문 론적 설탕입니다.


  • 사실, 이들 호출 중 어느 것도 스레드를 생성하지 않습니다. @Servy는await연산자 (더 구체적으로, 작업 대기열은 생성 된 코드에서 사용하는await연산자)가 기본값을 사용하고 있습니다SynchronizationContext스레드 풀 스레드에서 메서드 연속을 예약하는 방법 - Stephen Cleary
  • @StephenCleary : 아, 좋은 것. 메모 주셔서 감사. - Eric Lippert

-1

제어 처리는 동일한 스레드 내에서 수행되므로 루프가 실행 중일 때Consume방법은 그렇지 않다. 쓰레드를 사용한다면 반드시 그렇지 않을 수도 있습니다. 실제로 두 가지가 동시에 실행되기를 기대합니다.

동일한 스레드에 있다는 사실은 컨트롤이 코드의 일부에서 다른 코드로 전달 될 수 없다는 것을 의미하지는 않습니다. .NET (및 기타 모든 프레임 워크, AFAIK)은 원활하게 처리하며 각 부분은 아무런 문제없이 자체 컨텍스트로 실행됩니다.

그러나 두 스레드를 하나의 스레드에서 실행한다는 것은 whileConsume실행 중이면 루프가 중단됩니다. 만약Consume너무 오래 걸립니다. 정확히 사용자가인지 할 수 있습니다. Windows Forms를 처음 사용하는 많은 프로그래머가 GUI 컨트롤을 한꺼번에 너무 많은 정보를 채우면 양식이 멈추거나 때로는 공백으로 표시되는 것에 놀랐습니다. 화면을 새로 고치는 스레드는 제어 논리가 실행되는 스레드와 동일합니다. 백그라운드 작업 스레드를 사용하지 않습니다.


  • 컨트롤이 전달되는 원인Consume없이Produce명시 적으로 통제를 내리는가? .NET은Produce오래 동안 운영되어 왔고Consume(스레드 모델에서 OS의 역할과 유사)? - Matthew
  • 실제로 저는 Servy가 의견보다 나은 답변을 얻었습니다. - Renan

연결된 질문


관련된 질문

최근 질문