Jusqu'à récemment, j'avais supposé que la définition d'un élément d'un List<T>
via l'indexeur était thread-safe dans le contexte suivant.C# List <T> Sécurité des threads d'indexeur
// Assumes destination.Count >= source.Count
static void Function<T,U>(List<T> source, Func<T,U> converter, List<U> destination)
{
Parallel.ForEach(Partitioner.Create(0, source.Count), range =>
{
for(int i = range.Item1; i < range.Item2; i++)
{
destination[i] = converter(source[i]);
}
});
}
Depuis List<T>
stocke ses éléments dans un tableau interne et la mise en un par l'indice ne devrait pas nécessiter le redimensionnement, cela semblait être un pas raisonnable de la foi. En regardant le implementation de List<T>
dans .NET Core cependant, il semble que le setter de l'indexeur modifie un état interne (voir ci-dessous).
// Sets or Gets the element at the given index.
public T this[int index]
{
get
{
// Following trick can reduce the range check by one
if ((uint)index >= (uint)_size)
{
ThrowHelper.ThrowArgumentOutOfRange_IndexException();
}
Contract.EndContractBlock();
return _items[index];
}
set
{
if ((uint)index >= (uint)_size)
{
ThrowHelper.ThrowArgumentOutOfRange_IndexException();
}
Contract.EndContractBlock();
_items[index] = value;
_version++;
}
}
Alors dois-je supposer que List<T>
est thread-safe, même si chaque thread ne reçoit que/réglage des éléments de sa propre partie de la collection?
[Quelle est cette chose que vous appelez "thread safe"?] (Https://blogs.msdn.microsoft.com/ericlippert/2009/10/19/what-is-this-thing-you-call-thread -sûr/). La première chose que vous devez faire est de déterminer ce dont vous avez besoin pour être en sécurité. En ce qui concerne le code que vous regardez, je dirais que ce n'est pas sécurisé. Et vous ne devriez certainement pas supposer quoi que ce soit qui ne soit pas documenté en tant que thread-safe. Cependant, notez que le champ '_version' est utilisé pour un détail d'implémentation qui ne vous inquiète pas. Que ce soit modifié de manière imprévisible peut ne pas avoir d'importance pour vous. –
Si vous voulez la sécurité des threads, jetez un coup d'œil à [collections thread-safe] (https://msdn.microsoft.com/en-us/library/dd997305 (v = vs.110) .aspx) – Timo
Bien que vous soyez ce n'est pas vraiment le cas, mais il vaut peut-être mieux éviter de modifier l'état dans une boucle parallèle. Si la situation est que 'converter' est une opération de longue durée, il est préférable de calculer le résultat en utilisant' Parallel', puis d'affecter le résultat avec un seul thread. Essayez ceci: 'statique Liste Fonction (Liste source, Func convertisseur) {return source.AsParallel(). Sélectionnez (s => convertisseur (s)). ToList(); } ' –
Enigmativity