Tuesday, 7 May 2019

Where is the bug, bro?

I was recently ran into an interesting issue when using JsonConvert.DeserializeObject method within Parallel.ForEach function. 

Here is the code:


public class Temp
{
   public int A { get; set; }

   public string B { get; set; }
}


static async Task Main(string[] args)
{
    var counter = 0;
    Temp t = new Temp();
    var str = JsonConvert.SerializeObject(t);
    while (counter <= 25)
    {
       var itemsInList = new List<string>();
for (int i = 0; i < 10; i++)
       {
              itemsInList.Add(str);
}

var tempList = new List();
       Parallel.ForEach(itemsInList, (item) =>
       {
              var y = JsonConvert.DeserializeObject(item);
              tempList.Add(y);
});

       foreach (var tempItem in tempList)
       {
Console.WriteLine("A  :" + tempItem.A);
}
Console.Read();
       counter++;
    }
}


If we run this a few times, you will run into an odd "Object reference not set to an instance of an object" error.


Now that is odd as that is intermittent and that indicated that the issue was with Deserialization code. Well, it is not the case.

If you replace the Parallel.ForEach block with following, you will notice that the new logic is never run.

Parallel.ForEach(itemsInList, (item) =>
{
var y = JsonConvert.DeserializeObject(item);
       if(y == null)
       {
              Console.WriteLine("Some issue with deserialization");
}
tempList.Add(y);
});


Mystery deepens ??

Well, not really. As an experienced person would tell after a bit of head scratch, the issue is with List instance as that is not thread safe.

If we replace that with a ConcurrentBag, we are good.

var tempList = new ConcurrentBag();

Old knowledge but takes a minute to kick in. Nice!!

No comments:

Post a Comment