Task.Factory.StartNew 및 Task.Run 메서드에서

Task.Factory.StartNew 또는 Task.Run 메서드를 사용하여 작업을 만들 때 비동기 코드를 작성할 때 몇 가지 중요한 사항을 염두에 두어야합니다. 대부분의 경우 비동기 코드로 작업하는 경우 Task.Factory.StartNew 메서드를 사용하지 않는 것이 좋습니다. 병렬 코드로 작업하는 경우 StartNew가 좋은 선택이라고 말할 수 있습니다.

작업 스케줄러는 작업 예약을 담당하는 구성 요소입니다. .Net 프레임 워크는 두 가지 작업 스케줄러를 제공합니다. .Net 프레임 워크 스레드 풀에서 실행되는 기본 작업 스케줄러가 있고 지정된 대상의 동기화 컨텍스트에서 실행되는 작업 스케줄러가 있습니다. 기본 작업 스케줄러는 대부분의 경우 충분하지만 사용자 지정 작업 스케줄러를 구축하여 추가 기능을 제공 할 수도 있습니다. 사용자 지정 작업 스케줄러를 빌드하려면 System.Threading.Tasks.TaskScheduler 클래스를 확장하는 클래스를 만들어야합니다.

태스크 병렬 라이브러리를 사용하여 태스크를 어떻게 생성합니까?

.Net에서 작업을 만들고 시작할 수있는 몇 가지 방법이 있습니다. System.Threading.Tasks.Task 또는 System.Threading.Tasks.Task 클래스를 사용하여 작업 (예약 가능한 작업 단위)을 만들어야합니다. 전자는 값을 반환하지 않는 작업을 만드는 데 사용되지만 후자는 반환 값이있는 작업을 만드는 데 사용됩니다. Task.Factory 속성은 TaskFactory 클래스의 인스턴스입니다. 이 속성은 작업을 만들고 예약하는 데 사용됩니다. Task.Factory.StartNew 메서드는 포크 작업처럼 작동하고 새 작업을 만들고 시작하는 데 사용되지만 Wait 메서드는 조인 작업처럼 작동하며 작업이 완료 될 때까지 기다립니다.

다음 코드 조각은 Task.Factory.StartNew 메서드를 사용하는 방법을 보여줍니다.

Task.Factory.StartNew(() => TestMethod(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);

아래 코드 조각과 같이 Task.Run 메서드를 사용하여 Task를 만들 수도 있습니다.

public async Task DoSomeWork()

        {

            await Task.Run(() => TestMethod());

        }

        void TestMethod()

        {

            Console.WriteLine("Hello world!");

        }

Task에서 값을 반환하려면 아래 코드 스 니펫과 같이 Task.FromResult 메서드를 활용할 수 있습니다.

public async Task DoSomeWork()

   {

      string text = await Task.FromResult(GetMessage());

   }

private string GetMessage()

   {

      return "Hello world!";

   }

대리인 또는 작업을 사용하여 작업을 만들 수도 있습니다. 다음 코드 스 니펫은 작업 및 대리자를 사용하여 작업을 만드는 방법을 보여줍니다.

Task task1 = new Task (new Action(Display));

task1.Start();

Task task2 = new Task (delegate { Display(); });

task2.Start();

람바 및 익명 메서드를 사용하여 작업을 만들 수도 있습니다.

Task.Factory.StartNew 및 Task.Run

Task.Factory.StartNew는 작업을 만들고 시작하는 빠른 방법입니다. Task.Factory.StartNew에 대한 호출은 작업 인스턴스를 만든 다음 인스턴스에서 Start 메서드를 호출하는 것과 기능적으로 동일합니다. 그러나 많은 이유로 사용하지 않는 것이 좋습니다. 동기 코드를 실행하려는 경우 Task.Factory.StartNew는 좋은 선택이 아닙니다.

작업 스케줄러를 사용할 수있는 경우 StartNew 메서드는 해당 작업 스케줄러에서 작업을 실행합니다. 반대로 스케줄러를 사용할 수없는 경우 스레드 풀 스레드에서 작업을 실행합니다. Task.Factory.StartNew의 기본값은 TaskScheduler.Default가 아니라 TaskScheduler.Current입니다.

Task.Run (action)에 대한 호출은 다음 문과 동일합니다. Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

반대로 Task.Factory.StartNew (action)에 대한 호출은 다음 문과 동일합니다.

Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);

사용자 지정 작업 스케줄러를 생성하고 스케줄러 인스턴스를 명시 적으로 전달한 경우 Task.Factory.StartNew를 사용할 수 있습니다. Task.Run은 훨씬 간단하고 기본값이 더 안전하므로 항상 사용하는 것이 좋습니다. 즉, 작업 스케줄러를 만들 필요가없는 한 Task.Factory.StartNew 사용을 피해야하며, 새 작업을 만들고 예약하기 위해 StartNew 메서드를 호출 할 때 명시 적으로 전달해야합니다. TaskFactory.StartNew 메서드를 효과적이고 안정적으로 사용하려면 사용자 지정 작업 스케줄러를 사용한 다음 CancellationToken 및 TaskCreationOptions를 지정해야합니다.

Task.Run 메서드는 스레드 예약 및 그 복잡성을 세밀하게 제어 할 필요가 없을 때 사용하는 것이 좋습니다. 주로 CPU 바운드 메서드에서 Task.Run을 사용해야합니다. 그러나 태스크 구현 내부가 아니라 태스크를 호출하는 동안 Task.Run을 사용해야합니다. 즉, 메서드의 구현 내부가 아니라 메서드가 호출되는 지점에서 Task.Run을 사용해야합니다. 예를 들어, 다음 코드 조각은 "잘못된"코드 조각의 예입니다.

public async Task DownloadDataFromWebAsync(Uri uri)

        {

            return await Task.Run(() =>

            {

                using (WebClient webClient = new WebClient())

                {

                    return webClient.DownloadString(uri);

                }

            });

        }

위에 제공된 코드 스 니펫을 참조하십시오. 이 메서드는 백그라운드 스레드를 차단하고 스레드 풀에서 스레드를 검색하고 동 기적으로 실행되므로 확장 가능하지 않습니다. 따라서 시스템에서 더 많은 리소스를 소비합니다.