I've made some experimental Plinq query, and I'm not sure about the result can be corrupted or not.
Here is 3 different method, which provides the same result:
// unitTask is typeof Task<List<SomeEntity>>
//sequential version PLINQ
Console.WriteLine(unitTask.Result.Take(10)
.Aggregate(new StringBuilder(),
(text, current) => text.AppendFormat("@{0}sa{1}",
current.FullName.Substring(0, 3),
current.FullName.Substring(4)))
.ToString());
//parallel version PLINQ
Console.WriteLine(unitTask.Result.Take(10).AsParallel()
.Aggregate(new StringBuilder(),
(text, current) => text.AppendFormat("@{0}sa{1}",
current.FullName.Substring(0, 3),
current.FullName.Substring(4)))
.ToString());
//parallel version foreach with Partitioner
var output = new StringBuilder();
Parallel.ForEach(Partitioner.Create(unitTask.Result.Take(10)), r =>
{
//Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
output.AppendFormat("@{0}sa{1}", r.FullName.Substring(0, 3),
r.FullName.Substring(4));
});
Console.WriteLine(output.ToString());
My questions are:
Can I use StringBuilder
in PLINQ?
Due to append method is not thread safe as I know.
Or does it run in sequential mode in this case?
Parallel.Foreach runs the query in different threads, but result is the same as sequential Plinq.
Is it accidental, or it's smart and uses some synchronization?
This version doesn't use PLINQ, it uses the standard LINQ, so it's safe.
This version uses an overload of
Aggregate()
that's not safely parallelizable, so it will also execute on a single thread. This means it's safe, but it also won't be any faster than the sequential version.To actually take advantage of PLINQ, you would need to use another overload of
Aggregate()
that actually can execute in parallel. In your case that would mean having a separateStringBuilder
for each thread and then combine all theStringBuilder
s into one. Something like:This assumes that you don't care about the order of elements in the final string. If you do, this code won't work correctly.
This code modifies the same
StringBuilder
object from multiple threads.StringBuilder
is not thread-safe, so this code is not safe.