Verschil tussen de TPL & amp; async / af te wachten (Thread handling)

Proberen te begrijpen van het verschil tussen de TPL & amp; async/ awaitals het gaat om de schepping te rijgen.

Ik geloof dat de TPL (TaskFactory.StartNew) werkt vergelijkbaar met ThreadPool.QueueUserWorkItemin dat het een wachtrij te werken aan een draad in de draad zwembad. Dat is natuurlijk, tenzij u gebruik maken van TaskCreationOptions.LongRunning, die een nieuwe thread creëert.

Ik dacht dat async/ awaitzou werken net zo essentieel:

TPL:

Factory.StartNew( () => DoSomeAsyncWork() )
.ContinueWith( 
    (antecedent) => {
        DoSomeWorkAfter(); 
    },TaskScheduler.FromCurrentSynchronizationContext());

async/ Await

await DoSomeAsyncWork();  
DoSomeWorkAfter();

zou identiek zijn. Van wat ik heb gelezen lijkt het alsof async/ awaitonly “soms” maakt een nieuwe thread. Dus wanneer is er dan een nieuwe draad en wanneer is het niet een nieuwe thread? Als je te maken hadden met IO Completion Ports ik kan zien het niet hebben van een nieuwe thread te creëren, maar anders zou ik denk dat het zou moeten. Ik denk dat mijn begrip van FromCurrentSynchronizationContextaltijd een beetje vaag ook. Ik heb altijd dacht het was, in essentie, de UI thread.


Antwoord 1, Autoriteit 100%

Ik geloof dat de TPL (TaskFactory.Startnew) werkt vergelijkbaar met ThreadPool.QueueUserWorkItem in dat het een wachtrij te werken aan een draad in de draad zwembad.

Pretty much .

Van wat ik heb gelezen lijkt het alsof async / af te wachten alleen maar “soms” maakt een nieuwe thread.

Het is eigenlijk nooit doet. Als u wilt multithreading, je moet het zelf uit te voeren. Er is een nieuwe Task.Runmethode die is slechts korte weg voor Task.Factory.StartNew, en het is waarschijnlijk de meest voorkomende manier van het starten van een taak op de draad zwembad.

Als u te maken hadden met IO Completion Ports ik kan zien het niet hebben van een nieuwe thread te creëren, maar anders zou ik denk dat het zou moeten.

Bingo. Dus methoden zoals Stream.ReadAsyncook daadwerkelijk maken van een Taskwrapper rond een IOCP (als de Streamheeft een IOCP).

U kunt ook een aantal niet-I / O, niet-CPU “taken” te creëren. Een eenvoudig voorbeeld is Task.Delay, die een taak terugkeert dat completes na enige tijd.

Het koele ding over async/ awaitis dat je kunt wachtrij wat werk aan de thread pool (bijvoorbeeld Task.Run), doe wat I / O-gebonden bewerking (bijvoorbeeld Stream.ReadAsync), en doe een andere bewerking (bijvoorbeeld Task.Delay) … en ze zijn allemaal taken! Ze kunnen worden afgewacht of worden gebruikt in combinaties zoals Task.WhenAll.

Elke methode die terugkeert Taskkan awaited – het hoeft niet op een asyncmethode. Dus Task.Delayen I / O-gebonden activiteiten gewoon gebruik maken van TaskCompletionSourcete creëren en een taak uit te voeren – het enige wat wordt gedaan op de draad zwembad is de werkelijke voltooiing van de taak als de gebeurtenis plaatsvindt (timeout, I / O Completion, etc).

Ik denk dat mijn begrip van FromCurrentSynchronizationContext altijd was ook een beetje vaag. Ik heb altijd dacht het was, in essentie, de UI thread.

Ik schreef een artikel op SynchronizationContext. Het merendeel van de tijd, SynchronizationContext.Current

  • een gebruikersinterface context als de huidige thread is een UI thread.
  • een ASP.NET verzoekcontext als de huidige thread bedient een ASP.NET aanvraag.
  • een threadgroep anders is.

Elke draad kan stel een eigen SynchronizationContext, dus er zijn uitzonderingen op de bovenstaande regels.

Merk op dat de standaard Task-wachter de rest van de async-methode plant op de huidige SynchronizationContextals deze niet null is ; anders gaat het verder met de huidige TaskScheduler. Dit is vandaag niet zo belangrijk, maar in de nabije toekomst zal het een belangrijk onderscheid zijn.

Ik heb mijn eigen async/awaitintroop mijn blog, en Stephen Toub plaatste onlangs een uitstekende async/awaitVeelgestelde vragen.

Over “concurrency” versus “multithreading”, zie deze gerelateerde SO vraag. Ik zou zeggen dat asyncgelijktijdigheid mogelijk maakt, al dan niet multithreaded. Het is gemakkelijk om await Task.WhenAllof await Task.WhenAnyte gebruiken om gelijktijdige verwerking uit te voeren, en tenzij u expliciet de threadpool gebruikt (bijv. Task.Runof ConfigureAwait(false)), dan kunt u meerdere gelijktijdige bewerkingen tegelijkertijd uitvoeren (bijv. meerdere I/O of andere typen zoals Delay) – en er is geen draad voor nodig. Ik gebruik de term “single-threaded concurrency” voor dit soort scenario’s, hoewel je in een ASP.NET-host in feite kunt eindigen met “nul-threaded gelijktijdigheid”. Dat is best lief.


Antwoord 2, autoriteit 10%

async / wait vereenvoudigt in feite de ContinueWith-methoden ( Voortzettingen in Continuation Passing Stijl)

Het introduceert geen gelijktijdigheid – u moet dat nog steeds zelf doen (of de Async-versie van een framework-methode gebruiken. )

Dus de C# 5-versie zou zijn:

await Task.Run( () => DoSomeAsyncWork() );
DoSomeWorkAfter();

Other episodes