252 votes

Scénarios réels d'utilisation de TaskCompletionSource <T> ?

Je vais avoir du mal à comprendre : En quoi les scénarios TaskCompletionSource?

Autant que je sache , Tout ce qu'il sait, c'est qu'à un certain point, son SetResult ou SetException méthode est appelée à compléter l' Task<T> exposée en Task de la propriété.

En d'autres termes , il agit à titre de producteur pour un Task<TResult> et de son achèvement

J'ai vu ici l'exemple :

Si j'ai besoin d'un moyen pour exécuter une touche Func de manière asynchrone et ont une Tâche afin de représenter cette opération.

public static Task<T> RunAsync<T>(Func<T> function) 
{ 
    if (function == null) throw new ArgumentNullException("function"); 
    var tcs = new TaskCompletionSource<T>(); 
    ThreadPool.QueueUserWorkItem(_ => 
    { 
        try 
        {  
            T result = function(); 
            tcs.SetResult(result);  
        } 
        catch(Exception exc) { tcs.SetException(exc); } 
    }); 
    return tcs.Task; 
}

qui pourrait être utilisé si je n'avais pas Task.Factory.StartNew

Mais je n' ai Task.Factory.StartNew

Quelqu'un peut expliquer, par exemple, un scénario qui est liée directement à l' TaskCompletionSource et de ne pas hypothétique de la situation dans laquelle je n'ai pas d' Task.Factory.StartNew ?

279voto

GameScripting Points 2922

Je l’utilise surtout quand seulement un événement basé api est disponible (par exemple les sockets windows phone 8) :

Il est donc très utile lorsqu’il est utilisé conjointement avec le c# 5 `` mot clé.

93voto

SiLo Points 3513

Dans mes expériences, TaskCompletionSource est idéal pour l'emballage de vieux modèles asynchrones à la modernité de l' async/await modèle.

Le plus bénéfique exemple, je pense, lorsque l'on travaille avec des Socket. Il a la vieille APM et PAE des modèles, mais pas l' awaitable Task méthodes TcpListener et TcpClient ont.

Personnellement, j'ai plusieurs problèmes avec l' NetworkStream de la classe et préfèrent le raw Socket. L'être que j'aime aussi l' async/await modèle, j'ai fait une extension de la classe SocketExtender ce qui crée de nombreuses méthodes d'extension pour Socket.

L'ensemble de ces méthodes, l'utilisation de l' TaskCompletionSource<T> pour envelopper les appels asynchrones comme suit:

    public static Task<Socket> AcceptAsync(this Socket socket)
    {
        if (socket == null)
            throw new ArgumentNullException("socket");

        var tcs = new TaskCompletionSource<Socket>();

        socket.BeginAccept(asyncResult =>
        {
            try
            {
                var s = asyncResult.AsyncState as Socket;
                var client = s.EndAccept(asyncResult);

                tcs.SetResult(client);
            }
            catch (Exception ex)
            {
                tcs.SetException(ex);
            }

        }, socket);

        return tcs.Task;
    }

Je passe l' socket dans la BeginAccept méthodes de sorte que je reçois une légère augmentation des performances hors du compilateur de ne pas avoir réussi à hisser le paramètre local.

Ensuite, la beauté de tout cela:

 var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 listener.Bind(new IPEndPoint(IPAddress.Loopback, 2610));
 listener.Listen(10);

 var client = await listener.AcceptAsync();

40voto

Adi Lester Points 10814

Pour moi, un scénario classique pour l'utilisation de TaskCompletionSource , c'est quand il est possible que ma méthode n'aurez pas nécessairement avoir à faire un temps long de l'opération. Ce qu'il nous permet de le faire est de choisir les cas spécifiques où nous aimerions utiliser un nouveau thread.

Un bon exemple de cela est lorsque vous utilisez un cache. Vous pouvez avoir un GetResourceAsync méthode, qui a l'air dans le cache pour la ressource demandée et renvoie à la fois (sans l'aide d'un nouveau fil de discussion, en utilisant TaskCompletionSource) si la ressource a été trouvé. Seulement si la ressource n'a pas été trouvé, nous aimerions utiliser un nouveau fil de discussion, et de la récupérer à l'aide de Task.Run().

Un exemple de code peut être vu ici: Comment faire pour exécuter conditionnellement un code asynchonously à l'aide de tâches

19voto

Rahul Points 31

TaskCompletionSource est utilisé pour créer la Tâche des objets qui ne sont pas d'exécuter du code. Dans des Scénarios du Monde Réel TaskCompletionSource est idéal pour les I/O les opérations liées. De cette façon, vous obtenez tous les avantages de tâches (par exemple, les valeurs de retour, les continuations, etc) sans bloquer un thread pour la durée de l'opération. Si votre "fonction" est un IO opération il n'est pas recommandé de bloquer un thread à l'aide d'une nouvelle Tâche. Au lieu d'utiliser TaskCompletionSource vous pouvez créer un esclave tâche il vous suffit d'indiquer lors de votre I/O bound opération se termine ou les défauts.

3voto

Yaur Points 4362

J'monde réel scénario où je l'ai utilisé, TaskCompletionSource est lors de l'implémentation d'une file d'attente de téléchargement. Dans mon cas, si l'utilisateur commence 100 téléchargements je ne veux pas le feu tous à la fois et donc, au lieu de retourner un strated de la tâche I retour une tâche attaché TaskCompletionSource. Une fois que le téléchargement est achevé le thread de travail de la file d'attente termine la tâche.

Le concept clé ici est que je suis découplage lorsqu'un client demande une tâche doit être démarré à partir de quand il obtient réellement commencé. Dans ce cas, parce que je ne veux pas le client d'avoir à traiter avec la gestion des ressources.

notez que vous pouvez utiliser async/await .net 4, tant que vous êtes à l'aide de C# 5 compilateur (VS 2012+) voir ici pour plus de détails.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X