I had written a program that a list-builder method returns IEnumerable of string including lots of strings (1milion items) and I stored it in List of string , then it append all the items in a StringBuilder instance in a Parallel.Foreach. Then I printed stringBuilderInstance.Length .
The problem was that it was fewer than 1000000 . after some googling, I realized thet List collection is not Thread-Safe , and that causes this problem. So 2 solution crosses my mind :
1) Use lock
2) Use ConcurrentBag
When I am using lock , it is OK and the length is 1 milion , BUT :
when I am using ConcurrentBag of string , the length is fewer than I expected !
What is the underlying reason of this problem?
List-Creator method :
public static List<string> CreateList() { List<string> result = new List<string>(); for (int i = 0; i < 1000000; i++) { result.Add(1.ToString()); } return result; } Using ConcurrentBag :
public static void DoWithParallel_ThreadSafe() { ConcurrentBag<string> listOfString = new ConcurrentBag<string>(CreateList()); StringBuilder a = new StringBuilder(); Action<string> appender = (number) => { a.Append(number); }; Parallel.ForEach(listOfString, appender); Console.WriteLine($"The string builder lenght : {a.Length}"); } Using lock :
public static void DoWithParallel_UnsafeThread_Lock() { List<string> listOfString = CreateList(); StringBuilder a = new StringBuilder(); Action<string> appender = (number) => { lock (listOfString) { a.Append(number); } }; Parallel.ForEach(listOfString, appender); Console.WriteLine($"The string builder lenght : {a.Length}"); } Main :
static void Main(string[] args) { DoWithParallel_UnsafeThread_Lock(); DoWithParallel_ThreadSafe(); Console.ReadKey(); } Thank you in advance.