0
votes

I have problem with multi threading in .NET Framework 4.5 with await/async/whenall.

I called thousands of threads by calling in loop.

List<Task<string>> t = new List<Task<string>>(); 
for (Row = 0; Row < lines.Count; Row++)
{        
    t.Add(AccessPaymentVault(Row, credentials, cts.Token));
}
string[] str_list = await Task.WhenAll(t.ToArray());

AccessPaymentVault Function is used for connecting vault web service and retrieve credit card information.

async Task<string> AccessPaymentVault(int row, Credentials credentials, CancellationToken ct){
    var data = await Task.Run(() =>
    {
      return Tokenization.Retrieve(credentials, lines[row][CCColumnToken]);
    }, ct);

    return Encryptor.Decrypt(data);
}

Tokenization.Retrieve is the most waited function and it connects to webservice. WhenAll seems to be not waiting all tasks because some records in the result are randomly missing. When I first run, it retrieves all records. In second run, some records in the middle are missing. In third run, the missing records in second run was there but other records are missing.

I guess the problem is in WhenAll but not sure about it.

Any form of help is very appreciated.

Thank you.

1
This sounds a lot like stackoverflow.com/q/23936521/120955. Does Tokenization.Retrieve() act asynchronously by itself?StriplingWarrior
No it doesn't. That's why I used Task.Factory.StartNew for this function.sean
When you say "some records in the middle are missing," what do you mean? What code are you using to see which records are there?StriplingWarrior
in terms of using async/await everything looks fine. Just a couple of ideas: 1. there is a shared state in Tokenization.Retrieve which might be broken because of multithreading 2. you might swallow some exceptions inside the Tokenization.RetrieveMax
Max, you solved the problem! There was an exception raising because too many connections to the server. In catch section, I tried connecting again and it was solved. Write an answer and I will accept yours as answer. You saved me. thanks a lot!sean

1 Answers

3
votes

Nowadays the suggested way of starting a new task is Task.Run instead of Task.Factory.StartNew, unless you need a higher level of the control over the Task.

In your case, the main problem is that the result type will be Task, cause some nesting here. But luckily there is a way - Task.Unwrap.

So if you call the Task.Run - underneath Task.Factory.StartNew and the Task.Unwrap are called automatically.

Check out this link: http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx

And another good article: StartNew is Dangerous

Update from comments

In terms of using async/await everything looks fine. Just a couple of ideas:

  1. there is a shared state in Tokenization.Retrieve which might be broken because of multithreading
  2. you might swallow some exceptions inside the Tokenization.Retrieve