Ik heb deze constructie in mijn main()
, die
. creëert
var tasks = new List<Task>();
var t = Task.Factory.StartNew(
async () =>
{
Foo.Fim();
await Foo.DoBar();
});
//DoBar not completed
t.Wait();
//Foo.Fim() done, Foo.DoBar should be but isn't
Als ik echter .Wait
op t, wacht het niet tot de aanroep van DoBar()
is voltooid.
Hoe zorg ik ervoor dat het echt wacht?
Antwoord 1, autoriteit 100%
Het wordt afgeraden om Task.Factory.StartNew
te gebruiken met async-await
, in plaats daarvan zou u Task.Run
moeten gebruiken:
var t = Task.Run(
async () =>
{
Foo.Fim();
await Foo.DoBar();
});
De api Task.Factory.StartNew
is gebouwd vóór de Taakgebaseerd asynchroon patroon (TAP)en async-await
. Het retourneert Task<Task>
omdat je een taak start met een lambda-expressie die toevallig async is en dus een taak retourneert. Unwrap
zal de innerlijke taak extraheren, maar Task.Run
zal dat impliciet voor je doen.
Voor een diepere vergelijking is er altijd een relevant Stephen Toub-artikel: Task.Run vs Task.Factory.StartNew
Antwoord 2, autoriteit 6%
Het lijkt erop dat ik de gewenste functionaliteit krijg door Unwrap()
de taak uit te voeren.
Ik weet niet zeker of ik de redenering hierachter begrijp, maar ik veronderstel dat het werkt.
var t = Task.Factory.StartNew(
async () =>
{
Foo.Fim();
await Foo.DoBar();
}).Unwrap();
edit: ik heb gezocht naar ddescription van Unwrap()
:
Creates a proxy Task that represents the asynchronous operation of a Task<Task<T>>
vertegenwoordigt
Ik dacht dat dit traditioneel was wat de taak deed, maar als ik uitpakken moet bellen, denk ik dat dat prima is.
Antwoord 3
Ik had onlangs een soortgelijk probleem en kwam erachter dat je alleen maar DoBar()
een waarde hoeft te retourneren en .Result te gebruiken in plaats van te wachten.
var g = Task.Run(() => func(arg));
var val = g.Result;
Dit zal wachten tot func
zijn output retourneert en toewijst aan val.