나는 방법을 가지고있다 :
private static void Method()
{
Console.WriteLine("Method() started");
for (var i = 0; i < 20; i++)
{
Console.WriteLine("Method() Counter = " + i);
Thread.Sleep(500);
}
Console.WriteLine("Method() finished");
}
그리고이 작업을 새로운 작업에서 시작하고 싶습니다. 이 같은 새로운 작업을 시작할 수 있습니다
var task = Task.Factory.StartNew(new Action(Method));
아니면 이거
var task = Task.Run(new Action(Method));
그러나 Task.Run()
와 사이에 차이점이 있습니까 Task.Factory.StartNew()
? 둘 다 ThreadPool을 사용하고 Task 인스턴스를 만든 직후에 Method ()를 시작합니다. 첫 번째 변형을 사용해야 할 때와 두 번째 변형을 사용해야 할 때는 언제입니까?
답변
두 번째 방법 인 Task.Run
.NET 프레임 워크의 최신 버전 (.NET 4.5)에 도입되었습니다.
그러나 첫 번째 방법은 Task.Factory.StartNew
에서는 생성하려는 스레드에 대한 유용한 정보를 많이 정의 할 수 있지만 Task.Run
이를 제공하지는 않습니다.
예를 들어 오래 실행되는 작업 스레드를 생성한다고 가정 해 보겠습니다. 스레드 풀의 스레드가이 작업에 사용될 경우 스레드 풀의 남용으로 간주 될 수 있습니다.
이를 피하기 위해 할 수있는 한 가지는 별도의 스레드에서 작업을 실행하는 것입니다. 이 작업 전용이며 새로 완료된 스레드 는 작업이 완료되면 소멸됩니다. 아래와 같이을 사용하여이 작업을 수행 할 수 는 없지만 아래와 같이 Task.Run
수행 할 수 Task.Factory.StartNew
있습니다.
Task.Factory.StartNew(..., TaskCreationOptions.LongRunning);
여기 에 명시된 바와 같이 :
따라서 .NET Framework 4.5 Developer Preview에는 새로운 Task.Run 메서드가 도입되었습니다. 이것은 결코 Task.Factory.StartNew를
폐기하는 것이 아니라 단지 많은 매개 변수를 지정할 필요없이
Task.Factory.StartNew 를 사용하는 빠른 방법으로 생각 해야합니다. 바로 가기입니다. 실제로 Task.Run은 실제로 일부 기본 매개 변수를 전달하는 Task.Factory.StartNew에 사용 된 것과 동일한 논리로 구현됩니다. 작업을 작업에 전달할 때
Task.Run(someAction);
그것은 정확히 다음과 같습니다.
Task.Factory.StartNew(someAction,
CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
답변
사람들은 이미
Task.Run(A);
에 해당
Task.Factory.StartNew(A, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
그러나 아무도 언급하지 않았다
Task.Factory.StartNew(A);
다음과 같습니다.
Task.Factory.StartNew(A, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);
당신이 볼 수 있듯이 두 개의 매개 변수가 다릅니다 Task.Run
과 Task.Factory.StartNew
:
-
TaskCreationOptions
–Task.Run
사용TaskCreationOptions.DenyChildAttach
은 하위 태스크를 상위에 첨부 할 수 없음을 의미하며 다음을 고려하십시오.var parentTask = Task.Run(() => { var childTask = new Task(() => { Thread.Sleep(10000); Console.WriteLine("Child task finished."); }, TaskCreationOptions.AttachedToParent); childTask.Start(); Console.WriteLine("Parent task finished."); }); parentTask.Wait(); Console.WriteLine("Main thread finished.");
우리가 호출 할 때
parentTask.Wait()
,childTask
우리TaskCreationOptions.AttachedToParent
가 그것을 지정했지만 대기하지 않을 것 입니다. 왜냐하면TaskCreationOptions.DenyChildAttach
아이들이 첨부 할 수 없기 때문 입니다. 당신이 동일한 코드를 실행하면Task.Factory.StartNew
대신Task.Run
,parentTask.Wait()
기다리는childTask
때문에Task.Factory.StartNew
사용TaskCreationOptions.None
-
TaskScheduler
-usesTask.Run
는TaskScheduler.Default
기본 작업 스케줄러 (스레드 풀에서 작업을 실행하는 스케줄러)가 항상 작업을 실행하는 데 사용됨을 의미합니다.Task.Factory.StartNew
반면TaskScheduler.Current
에 현재 스레드의 스케줄러를 의미하는 사용은TaskScheduler.Default
항상 그렇지는 않습니다. 실제로 개발Winforms
또는WPF
응용 프로그램을 개발할 때 현재 스레드에서 UI를 업데이트해야합니다.이 사람들이TaskScheduler.FromCurrentSynchronizationContext()
작업 스케줄러를 사용하려면TaskScheduler.FromCurrentSynchronizationContext()
스케줄러 를 사용하는 작업 내에서 다른 오래 실행되는 작업을 실수로 만들면 UI가 고정됩니다. 이에 대한 자세한 설명은 여기를 참조하십시오.
따라서 일반적으로 중첩 하위 작업을 사용하지 않고 스레드 풀에서 항상 작업을 실행하려는 Task.Run
경우 좀 더 복잡한 시나리오가없는 한 사용하는 것이 좋습니다 .
답변
차이점을 설명하는 이 블로그 기사 를 참조하십시오 . 기본적으로
Task.Run(A)
하는 것과 같습니다 :
Task.Factory.StartNew(A, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
답변
은 Task.Run
새로운 .NET 프레임 워크 버전에 도입되었다 그것은됩니다 추천 .
.NET Framework 4.5부터는 Task.Run 메서드가 계산 바운드 작업을 시작하는 데 권장되는 방법입니다. 장시간 실행되는 컴퓨팅 바운드 작업에 대해 세밀한 제어가 필요한 경우에만 StartNew 방법을 사용하십시오.
(가) Task.Factory.StartNew
더 많은 옵션을 가지고는이 Task.Run
속기이다 :
Run 메서드는 기본값을 사용하여 작업을 쉽게 시작할 수있는 일련의 오버로드를 제공합니다. StartNew 과부하에 대한 간단한 대안입니다.
그리고 속 기어로 나는 기술적 지름길을 의미합니다 .
public static Task Run(Action action)
{
return Task.InternalStartNew(null, action, null, default(CancellationToken), TaskScheduler.Default,
TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, ref stackMark);
}
답변
Stephen Cleary의이 게시물에 따르면 Task.Factory.StartNew ()는 위험합니다.
블로그와 Task.Factory.StartNew를 사용하여 백그라운드 스레드에서 작업을 시작하는 질문에 많은 코드가 있습니다. Stephen Toub에는 Task.Run이 Task.Factory.StartNew보다 나은 이유를 설명하는 훌륭한 블로그 기사가 있지만 많은 사람들이 읽지 않았거나 이해하지 못하는 것 같습니다. 그래서 나는 같은 주장을 취하고 좀 더 강력한 언어를 추가했으며 이것이 어떻게 진행되는지 볼 것입니다.
StartNew는 Task.Run보다 더 많은 옵션을 제공하지만, 우리가 볼 수 있듯이 매우 위험합니다. 비동기 코드에서 Task.Factory.StartNew보다 Task.Run을 선호해야합니다.
실제 이유는 다음과 같습니다.
- 비동기 대리자를 이해하지 못합니다. StartNew를 사용하려는 이유에서 이것은 실제로 포인트 1과 동일합니다. 문제는 StartNew에 비동기 대리자를 전달할 때 반환 된 작업이 해당 대리자를 나타내는 것으로 가정하는 것이 당연하다는 것입니다. 그러나 StartNew는 비동기 대리자를 이해하지 못하므로 해당 작업이 실제로 나타내는 것은 해당 대리자의 시작일뿐입니다. 이것은 비동기 코드에서 StartNew를 사용할 때 코더가 겪는 첫 번째 함정 중 하나입니다.
- 혼란스러운 기본 스케줄러. 좋습니다, 질문 시간 트릭 : 아래 코드에서 “A”메소드는 어떤 스레드에서 실행됩니까?
Task.Factory.StartNew(A);
private static void A() { }
글쎄, 당신은 그것이 까다로운 질문이라는 것을 알고 있습니까? “스레드 풀 스레드”라고 답한 경우 죄송합니다. 그러나 올바르지 않습니다. “A”는 현재 실행중인 TaskScheduler에서 실행됩니다!
따라서 작업이 완료되고 Stephen Cleary가 자신의 게시물에서 더 자세하게 설명하는 것처럼 연속으로 인해 UI 스레드에서 마샬링 될 수 있습니다.
필자의 경우, 바쁜 애니메이션을 표시하면서 뷰의 데이터 그리드를로드 할 때 백그라운드에서 작업을 실행하려고했습니다. 사용 중일 때 바쁜 애니메이션이 Task.Factory.StartNew()
표시되지 않았지만로 전환했을 때 애니메이션이 올바르게 표시되었습니다 Task.Run()
.
자세한 내용은 https://blog.stephencleary.com/2013/08/startnew-is-dangerous.html을 참조 하십시오
답변
Task.Factory.StartNew ()의 약어 인 Task.Run ()과 유사하지만 동기화 및 비동기 대리자의 경우 동작간에 약간의 차이가 있습니다.
다음 두 가지 방법이 있다고 가정하십시오.
public async Task<int> GetIntAsync()
{
return Task.FromResult(1);
}
public int GetInt()
{
return 1;
}
이제 다음 코드를 고려하십시오.
var sync1 = Task.Run(() => GetInt());
var sync2 = Task.Factory.StartNew(() => GetInt());
여기서 sync1과 sync2는 모두 Task <int> 유형입니다.
그러나 비동기 메소드의 경우 차이점이 있습니다.
var async1 = Task.Run(() => GetIntAsync());
var async2 = Task.Factory.StartNew(() => GetIntAsync());
이 시나리오에서 async1은 Task <int> 유형이지만 async2는 Task <Task <int>> 유형입니다.
답변
두 개의 서비스를 호출하는 응용 프로그램에서 Task.Run과 Task.Factory.StartNew를 모두 비교 했습니다 . 내 경우에는 둘 다 잘 작동한다는 것을 알았습니다. 그러나 두 번째는 더 빠릅니다.