Vous pourriez accomplir cela beaucoup plus facilement. Notez que l'utilisation du constructeur Task n'est généralement pas nécessaire ou recommandée, la mutation de l'état d'un objet particulier peut être difficile à suivre ou à déboguer. Retourner un nouvel objet qui représente votre état souhaité vous permettra d'appliquer un état valide minimum. Le code suivant traite tous vos éléments et renvoie les éléments terminés à votre code client.
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Processing {
public class MyProcessor {
public async Task<IEnumerable<Subscription>> ProcessSubscriptionRequestsAsync(IEnumerable<SubscriptionRequest> subscriptionRequests) {
var subscriptionProcessingTasks = subscriptionRequests.Select(request => ProcessSubscriptionForASingleRecord(request)).ToArray();
return await Task.WhenAll(subscriptionProcessingTasks);
}
public async Task<Subscription> ProcessSubscriptionForASingleRecord(SubscriptionRequest request) {
//process the request
try {
var subscription = await Context.ProcessRequest(request);
return subscription;
} catch {
//something went wrong with the request
}
}
}
public class SubscriptionRequest {
//A subcription request
}
public class Subscription {
//A completed subscription request
}
}
Mise à jour
Il pourrait aider si vous pouvez exclure un nouvel abonnement de classe et ajouter la solution dans votre réponse. Je l'essaierai ensuite
Espérons que l'aperçu simplifié avant et après sera plus facile à intégrer. La principale différence est de remplacer le Parallel.ForEach
avec un Select
pour créer votre collection de tâches sans avoir besoin de prendre un verrou sur la liste des tâches pour chaque SubscriptionRequest
, également de mettre en parallèle Task
s en parallèle n'est généralement pas nécessaire car chacun d'entre eux sera exécuté de manière asynchrone seul gain atteindre un point où tous sont en attente plus tôt, pas finissant. Ensuite, chaque tâche est autorisée à démarrer et toutes sont attendues au await Task.WhenAll(tasks)
. Il sera important pour vous de déterminer quel type de traitement chaque SubscriptionRequest
subit. Par souci d'exemple j "ai fait l'hypothèse que chaque demande est en quelque sorte lié à l'accès de base de données, à savoir le stockage de la demande, la mise à jour d'un profil utilisateur de toutes sortes etc ..
public class OriginalSynchronous {
public void ProcessSubscriptionRequest() {
List<SubscriptionRequest> lstSubscriptionRequests = FromSomeResource();
List<Task> tsk = new List<Task>();
Parallel.ForEach(lstSubscriptionRequests, objSubscriptionRequest => {
var oTsk =
new Task(
() => ProcessSubscriptionForASingleRecord(objSubscriptionRequest));// update some properties after processing SubscriptionRequest
oTsk.Start();
lock (tsk) {
tsk.Add(oTsk);
}
});
Task.WaitAll(tsk.ToArray());
}
private void ProcessSubscriptionForASingleRecord(SubscriptionRequest request) {
//modify SubscriptionRequest
}
}
public class ModifiedAsync {
public async Task ProcessSubscriptionRequest() {
var subscriptionRequests = await FromSomeResourceAsync();
var tasks = subscriptionRequests.Select(request => {
return ProcessSubscriptionForASingleRecord(request);
}).ToArray();
await Task.WhenAll(tasks);
}
public async Task ProcessSubscriptionForASingleRecord(SubscriptionRequest request) {
//modify SubscriptionRequest
}
}
Ne créez pas une tâche par vous-même, utilisez 'wait' ou' Task.Run' Vos tâches ne commencent pas du tout – VMAtm
Pouvez-vous m'aider à corriger le code ci-dessus? –
Pourquoi créez-vous des tâches froides comme celle-ci et pourquoi utilisez-vous le verrouillage lorsque vous êtes * still * sur le thread principal? Votre code ne contient pas non plus 'Parallel.ForEach', ou n'importe quel code pour partager l'état.Il est impossible de répondre comme ceci.Par exemple' Parallel.ForEach (lstSubscriptionRequests, ProcessSubscriptionForASingleRecord) 'est équivalent à ceci Pourquoi n'utilisez-vous pas? Si 'ProcessSubscription..' produit des résultats, utilisez PLINQ, par exemple' from subscription dans lstSubscriptionRequests.AsParallel() sélectionnez ProcessSubscriptionForASingleRecord (abonnement) ' –