Mam metodę:
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");
}
I chcę rozpocząć tę metodę w nowym zadaniu. Mogę rozpocząć nowe zadanie w ten sposób
var task = Task.Factory.StartNew(new Action(Method));
albo to
var task = Task.Run(new Action(Method));
Ale czy jest jakaś różnica między Task.Run()
i Task.Factory.StartNew()
. Obaj używają ThreadPool i uruchamiają Method () natychmiast po utworzeniu instancji zadania. Kiedy powinniśmy użyć pierwszego wariantu, a kiedy drugiego?
c#
multithreading
task-parallel-library
Sergiy Lichenko
źródło
źródło
StartNew
domyślnie zastosowania,TaskScheduler.Current
które mogą być pulą wątków, ale mogą być także wątkiem interfejsu użytkownika.Odpowiedzi:
Druga metoda
Task.Run
została wprowadzona w późniejszej wersji środowiska .NET (w .NET 4.5).Jednak pierwsza metoda
Task.Factory.StartNew
daje możliwość zdefiniowania wielu przydatnych rzeczy na temat wątku, który chcesz utworzyć, aTask.Run
nie zapewnia tego.Załóżmy na przykład, że chcesz utworzyć długo działający wątek zadania. Jeśli do tego zadania zostanie użyty wątek z puli wątków, można to uznać za nadużycie puli wątków.
Aby tego uniknąć, wystarczy uruchomić zadanie w osobnym wątku. Nowo utworzony wątek, który byłby poświęcony temu zadaniu i zostałby zniszczony po zakończeniu zadania. Nie możesz tego
Task.Run
zrobić za pomocą , podczas gdy możesz to zrobić za pomocąTask.Factory.StartNew
, jak poniżej:Jak stwierdzono tutaj :
źródło
that’s exactly equivalent to
nie ma instrukcja Statemente .tha's exactly equivalent to
nie zawiera. Z góry dziękuję. Byłoby miło wyjaśnić z komentarzem do twojego kodu. Dzięki :)TaskScheduler.Default
. Proszę zajrzeć tutaj odniesieniaource.microsoft.com/#mscorlib/system/threading/Tasks/… .Ludzie już o tym wspominali
Jest równa
Ale nikt o tym nie wspominał
Jest równa:
Jak widać, dwa parametry są różne dla
Task.Run
iTask.Factory.StartNew
:TaskCreationOptions
-Task.Run
zastosowania,TaskCreationOptions.DenyChildAttach
co oznacza, że zadania dla dzieci nie mogą być przypisane do rodzica, rozważ to:Kiedy będziemy wzywać
parentTask.Wait()
,childTask
nie będziemy oczekiwać, nawet jeśli postanowiliśmyTaskCreationOptions.AttachedToParent
,TaskCreationOptions.DenyChildAttach
dzieje się tak dlatego, że zabrania dzieciom przyłączania się do niego. Jeśli uruchomisz ten sam kodTask.Factory.StartNew
zamiastTask.Run
,parentTask.Wait()
zaczeka na,childTask
ponieważTask.Factory.StartNew
używaTaskCreationOptions.None
TaskScheduler
-Task.Run
Używa,TaskScheduler.Default
co oznacza, że do uruchamiania zadań zawsze będzie używany domyślny harmonogram zadań (ten, który uruchamia zadania w puli wątków).Task.Factory.StartNew
z drugiej strony używa,TaskScheduler.Current
co oznacza harmonogram bieżącego wątku, może być,TaskScheduler.Default
ale nie zawsze. W rzeczywistości podczas programowaniaWinforms
lubWPF
aplikacji wymagana jest aktualizacja interfejsu użytkownika z bieżącego wątku, aby to zrobić, ludzie używająTaskScheduler.FromCurrentSynchronizationContext()
harmonogramu zadań, jeśli przypadkowo utworzysz inne długo działające zadanie w ramach zadania, które korzystało zTaskScheduler.FromCurrentSynchronizationContext()
harmonogramu, interfejs użytkownika zostanie zawieszony. Bardziej szczegółowe wyjaśnienie tego można znaleźć tutajOgólnie więc, jeśli nie używasz zadania zagnieżdżonego i zawsze chcesz, aby twoje zadania były wykonywane w puli wątków, lepiej jest użyć
Task.Run
, chyba że masz bardziej złożone scenariusze.źródło
Zobacz ten artykuł na blogu, który opisuje różnicę. Zasadniczo robienie:
To jest to samo co robienie:
źródło
Został
Task.Run
wprowadzony w nowszej wersji .NET Framework i jest zalecany .Task.Factory.StartNew
Ma więcej opcji,Task.Run
jest skrótem:I przez skrót mam na myśli techniczny skrót :
źródło
Zgodnie z tym postem Stephena Cleary'ego Task.Factory.StartNew () jest niebezpieczny:
Oto rzeczywiste powody:
Oznacza to, że może potencjalnie działać w wątku interfejsu użytkownika, jeśli operacja zostanie zakończona, a następnie powróci do wątku interfejsu użytkownika z powodu kontynuacji, jak Stephen Cleary wyjaśnia pełniej w swoim poście.
W moim przypadku próbowałem uruchomić zadania w tle podczas ładowania siatki danych dla widoku, jednocześnie wyświetlając zajętą animację. Animacja zajętości nie wyświetlała się podczas używania,
Task.Factory.StartNew()
ale animacja wyświetlała się poprawnie po przełączeniu naTask.Run()
.Aby uzyskać szczegółowe informacje, zobacz https://blog.stephencleary.com/2013/08/startnew-is-dangerous.html
źródło
Oprócz podobieństw, tj. Task.Run () jest skrótem od Task.Factory.StartNew (), istnieje niewielka różnica między ich zachowaniem w przypadku delegowania synchronizacji i asynchronizacji.
Załóżmy, że istnieją dwie metody:
Teraz rozważ następujący kod.
Tutaj zarówno sync1, jak i sync2 są typu Zadanie <int>
Różnica pojawia się jednak w przypadku metod asynchronicznych.
W tym scenariuszu async1 jest typu Zadanie <int>, jednak async2 jest typu Zadanie <Zadanie <int>>
źródło
Task.Run
ma wbudowaną funkcję rozpakowywaniaUnwrap
metody. Oto post na blogu, który wyjaśnia uzasadnienie tej decyzji.W mojej aplikacji, która wywołuje dwie usługi, porównałem zarówno Task.Run, jak i Task.Factory.StartNew . Odkryłem, że w moim przypadku oba działają dobrze. Jednak drugi jest szybszy.
źródło