0
votes

Retourner plusieurs valeurs asynchrones

J'ai l'obligation de calculer ces deux tâches indépendantes.Arlier, je le faisais en série comme: xxx

et la méthode calculatemd5hash est utilisé. Pour calculer les valeurs de hachage MD5 pour les fichiers aussi gros que 16 Go: xxx

mais depuis que ces 2 calcululatemd5hash peuvent exécuter en parallèle, j'essayais ceci: xxx

et mon calculatemd5 méthode ressemble à: xxx

J'espérais le code à travailler de manière asynchrone, mais cela fonctionne de manière synchrone.


1 commentaires

Une méthode est asynchrone lorsqu'elle renvoie une tâche incomplète . La tâche renvoyée par la méthode calculaTemd5 est toujours terminée, car il n'y a pas de attendre à l'intérieur de cette méthode, il fonctionne donc du début à la fin de manière synchrone. Pour un gethashasync véritablement asynchrone look ici . Btw selon le Directives La méthode calculatemd5 doit être nommée calculatemd5async


3 Réponses :


3
votes

Ceci est susceptible d'être I / O LIMITED, de sorte que la paralletiquité ne rende probablement pas beaucoup de choses (et même pourrait même ralentir les choses).

Cela dit, le problème avec votre code est que vous n'êtes pas Création de nouvelles tâches pour exécuter le code en arrière-plan (simplement spécifier async ne crée aucun thread).

plutôt que d'essayer de "forcer" il utilisera l'ASYNC, le La solution la plus facile est probablement d'exploiter PLINQ via 7 commentaires

J'ai essayé: Files.Asparallel (). Sélectionnez (Calculez TEMD5) .tolist (). Mais le problème est que je dispose de 17 Go de nom de fichier "MyName" et 17 Go avec nom de fichier "noname". Avec la solution fournie, il faut environ 7 minutes, tandis que lorsque je calculais des valeurs de hachage en série, il prenait environ 5 minutes.So, d'une manière dont la performance n'est pas améliorée des byfiles.Asparallall (). Sélectionnez (2). Calcu Latemd5) .tolist ()


Ce n'est pas I / O LIMITED.J'ai une liste de fichiers de liste prédéfinis.


@ user11708636 Ce n'est pas I / O LIMITE.J'ai une liste de liste Fichiers prédéfinie. Mais vous lisez les données du disque à l'aide de File.OpenRead (nom de fichier) qui fait des E / S. Étant donné que les fichiers sont de 17 Go chacun, vous auriez besoin d'au moins 34 Go de RAM si vous maintenez les données en mémoire ... It est E / S Bound, et le fait qu'il reste plus lent lors de la lecture de la Les fichiers simultanément en résultent de cela.


Depuis que j'ai la RAM de 32 Go .1) Est-ce que la programmation parallèle prendra plus de temps que la programmation en série en raison de la RAM insuffisante? 2) Il sera donc préférable d'exécuter ces 2 tâches séquentielles plutôt que parallèlement?


@ user11708636 Dans ce cas particulier, oui: car il est obligé d'E / S, il est plus rapide de traiter les fichiers séquentiellement depuis que vous essayez de lire simultanément deux fichiers. Il est possible d'accélérer cela si vous pouvez lire des morceaux à partir d'un fichier et que différents morceaux sont traités par différents threads - mais vous ne pouvez pas le faire avec MD5.Compeauhash () . Notez que la lecture des fichiers simultanément peut être plus rapide dans certains cas, par ex. Si les fichiers sont sur deux disques durs différents ou si elles sont sur un SSD.


** Notez que la lecture des fichiers simultanément peut être plus rapide dans certains cas **. Mais puisque la transformation utilise RAM de 32 Go, donc le problème des E / S ne continuera-t-il pas, mais dans une légère mesure moindre?


@ user11708636 Le traitement n'utilise pas 32g de RAM - le fichier est traité en morceaux. Vous n'auriez besoin que de tout ce que la RAM si vous lisez chaque fichier dans la mémoire avant de le traiter. Cependant, vous pouvez lire le fichier dans un fil et le traiter dans un fil séparé. Je posterai cette approche comme une réponse séparée dans une minute ou deux.



2
votes

Vous pouvez modifier la fonction de fonction en tâche, puis attendez le résultat.

private async Task<string> CalculateMD5(string filename)
{
    return await Task.Run(() =>
    {
        using (var md5 = MD5.Create())
        {
            using (var stream = File.OpenRead(filename))
            {
                var hash = md5.ComputeHash(stream);
                return BitConverter.ToString(hash).Replace("-", string.Empty).ToLowerInvariant();
            }
        }
    });
}


0 commentaires

2
votes

Un moyen d'accélérer ce haut consiste à utiliser un double tampon de sorte que un thread peut être lu dans le fichier dans un tampon, tandis que le MD5 est calculé pour un autre tampon.

Ceci vous permet de chevaucher le i / O avec le calcul. P>

Le meilleur moyen de le faire serait d'avoir une tâche unique qui était responsable du calcul du MD5 pour tous les blocs de données, mais comme cela complique un peu le code (et n'est pas susceptible de donner beaucoup de résultats de bien meilleurs), je vais plutôt créer une nouvelle tâche pour chaque bloc. P>

Le code ressemble à ceci: p>

ComputeMd5Async() Took 00:00:04.8066365
49, 54, 154, 19, 115, 198, 28, 163, 5, 182, 183, 91, 2, 5, 241, 253

ComputeMd5() Took 00:00:06.9654982
49, 54, 154, 19, 115, 198, 28, 163, 5, 182, 183, 91, 2, 5, 241, 253

ComputeMd5Async() Took 00:00:04.7018911
49, 54, 154, 19, 115, 198, 28, 163, 5, 182, 183, 91, 2, 5, 241, 253

ComputeMd5() Took 00:00:07.3552470
49, 54, 154, 19, 115, 198, 28, 163, 5, 182, 183, 91, 2, 5, 241, 253

ComputeMd5Async() Took 00:00:04.6536709
49, 54, 154, 19, 115, 198, 28, 163, 5, 182, 183, 91, 2, 5, 241, 253

ComputeMd5() Took 00:00:06.9807878
49, 54, 154, 19, 115, 198, 28, 163, 5, 182, 183, 91, 2, 5, 241, 253

ComputeMd5Async() Took 00:00:04.7271215
49, 54, 154, 19, 115, 198, 28, 163, 5, 182, 183, 91, 2, 5, 241, 253

ComputeMd5() Took 00:00:07.4089941
49, 54, 154, 19, 115, 198, 28, 163, 5, 182, 183, 91, 2, 5, 241, 253


0 commentaires