According to MSDN, async
e await
non creare nuove discussioni:asincrona Understanding/attendono senza fili
I
async
eawait
parole chiave non causano ulteriori thread da creare.
Con questo in mente, ho difficoltà a capire il flusso di controllo di alcuni programmi semplici. Il mio esempio completo è qui sotto. Si noti che richiede lo Dataflow library, che è possibile installare da NuGet.
using System;
using System.Threading.Tasks.Dataflow;
namespace TaskSandbox
{
class Program
{
static void Main(string[] args)
{
BufferBlock<int> bufferBlock = new BufferBlock<int>();
Consume(bufferBlock);
Produce(bufferBlock);
Console.ReadLine();
}
static bool touched;
static void Produce(ITargetBlock<int> target)
{
for (int i = 0; i < 5; i++)
{
Console.Error.WriteLine("Producing " + i);
target.Post(i);
Console.Error.WriteLine("Performing intensive computation");
touched = false;
for (int j = 0; j < 100000000; j++)
;
Console.Error.WriteLine("Finished intensive computation. Touched: " + touched);
}
target.Complete();
}
static async void Consume(ISourceBlock<int> source)
{
while (await source.OutputAvailableAsync())
{
touched = true;
int received = source.Receive();
Console.Error.WriteLine("Received " + received);
}
}
}
}
uscita:
Producing 0
Performing intensive computation
Received 0
Finished intensive computation. Touched: True
Producing 1
Performing intensive computation
Received 1
Finished intensive computation. Touched: True
Producing 2
Performing intensive computation
Received 2
Finished intensive computation. Touched: False
Producing 3
Performing intensive computation
Received 3
Finished intensive computation. Touched: False
Producing 4
Performing intensive computation
Received 4
Finished intensive computation. Touched: True
Questo sembra indicare che Consume
è dato comando mentre il ciclo for
è in esecuzione, come il compito OutputAvailableAsync
completa:
for (int j = 0; j < 100000000; j++)
;
Questo sarebbe sorprendente in un modello filettato. Ma se non sono coinvolti ulteriori thread, come può il controllo di resa Produce
nel mezzo del ciclo for
?
@ I4V: la risposta a tale domanda afferma che "è necessario che tutte le operazioni di blocco producano esplicitamente il controllo utilizzando il modello async/await". Ma nella mia domanda, il controllo passa da 'Produce' a' Consume' senza 'Produce' che dà un controllo esplicito. Questa è la parte di cui sono confuso. –
@Matthew Poiché questa è un'applicazione Console non c'è 'SynchronizationContext', il che significa che tutti i callback delle chiamate' await' vanno a 'SynchronizationContext.Default', che è il pool di thread, quindi tecnicamente ci sono in realtà due thread in esecuzione a volte durante l'esecuzione di questo programma. Per evitare la creazione di thread aggiuntivi è necessario creare il proprio contesto di sincronizzazione personalizzato e impostarlo. Se lo facessi, vedresti che le chiamate "Recieved" non saranno chiamate fino a quando tutta la produzione non è stata fatta specificatamente perché non stai * producendo controllo mentre produci. – Servy
@Servy: se ci sono più thread coinvolti, perché MSDN afferma che "In particolare, questo approccio è migliore di BackgroundWorker per le operazioni legate all'IO perché ... non è necessario proteggersi dalle condizioni di gara"? Ho modificato il mio esempio per aggiungere una semplice condizione di gara. –