2

I'm using the .NET API available from parse.com,

https://parse.com/docs/dotnet_guide#objects-saving

A snippet of my code looks like this;

public async void UploadCurrentXML()
{
   ...
   var query = ParseObject.GetQuery("RANDOM_TABLE").WhereEqualTo("some_field", "string");
   var count = await query.CountAsync();
   ParseObject temp_A;
   temp_A = await query.FirstAsync();
   ...
   // do lots of stuff
   ...
   await temp_A.SaveAsync();
}

To summarize; A query is made to a remote database. From the result a specific object (or its reference) is obtained from the database. Multiple operations are performed on the object and in the end, its saved back into the database.

All the database operations happen via await ParseObject.randomfunction() . Is it possible to call these functions in a synchronous manner? Or at least wait till the operation returns without moving on? The application is designed for maintenance purposes and time of operation is NOT an issue.

I'm asking this because as things stand, I get an error which states

The number of count operations in progress has reached its limit.

I've tried,

var count = await query.CountAsync().ConfigureAwait(false);

in all the await calls, but it doesn't help - the code is still running asynchronously.

var count = query.CountAsync().Result;

causes the application to get stuck - fairly certain that I've hit a deadlock.

A bit of searching led me to this question,

How would I run an async Task<T> method synchronously?

But I don't understand how it could apply to my case, since I do not have access to the source of ParseObject. Help? (Am using .NET 4.5)

Community
  • 1
  • 1
chronodekar
  • 2,616
  • 6
  • 31
  • 36
  • Why not use the synchronous versions of the methods you are using? e.g. `Count()`, `First()`? – Mister Epic Feb 04 '14 at 12:52
  • Sadly, they don't exist. I would have tried them otherwise. :( – chronodekar Feb 04 '14 at 12:55
  • What type is `query`? – Mister Epic Feb 04 '14 at 13:04
  • new Task(UploadCurrentXML).RunSynchronously(); – Hans Passant Feb 04 '14 at 13:19
  • Does this help? https://www.google.com/webhp?complete=1&hl=en#complete=1&hl=en&q=How+to+call+an+asynchronous++method+synchronously%3F Plenty of answers. – usr Feb 04 '14 at 13:35
  • @usr: Meh. The [top result](http://stackoverflow.com/questions/5095183/how-would-i-run-an-async-taskt-method-synchronously) is a dangerous hack that should be strongly avoided. – Stephen Cleary Feb 04 '14 at 13:37
  • @StephenCleary honestly, I didn't look. It just seemed like a common enough problem. Can you recommend some article that thoroughly treats this subject? I'd be interested in it myself. – usr Feb 04 '14 at 13:39
  • 1
    @usr: The best resource is [this blog post](http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx), which (briefly) covers all the approaches, and notes that there is no general-purpose solution. – Stephen Cleary Feb 04 '14 at 13:52
  • @HansPassant it's not UploadCurrentXML that I want to run synchronously, but query.CountAsync(). For that matter, I think I tried your approach, but had compiling problems because of the return type – chronodekar Feb 04 '14 at 17:23
  • @chronodekar, check this: [Task sequencing and re-entracy](http://stackoverflow.com/questions/21424084/task-sequencing-and-re-entracy). – noseratio Feb 04 '14 at 22:10

2 Answers2

4

I recommend that you use asynchronous programming throughout. If you're running into some kind of resource issue (i.e., multiple queries on a single db not allowed), then you should structure your code so that cannot happen (e.g., disabling UI buttons while operations are in flight). Or, if you must, you can use SemaphoreSlim to throttle your async code:

private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1);
public async Task UploadCurrentXMLAsync()
{
  await _mutex.WaitAsync();
  try
  {
    ...
    var query = ParseObject.GetQuery("RANDOM_TABLE").WhereEqualTo("some_field",  "string");
    var count = await query.CountAsync();
    ParseObject temp_A;
    temp_A = await query.FirstAsync();
    ...
    // do lots of stuff
    ...
    await temp_A.SaveAsync();
  }
  finally
  {
    _mutex.Release();
  }
}

But if you really, really want to synchronously block, you can do it like this:

public async Task UploadCurrentXMLAsync();

Task.Run(() => UploadCurrentXMLAsync()).Wait();

Again, I just can't recommend this last "solution", which is more of a hack than a proper solution.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Wow. I've seen your replies on the other answers, but never expected you to help me too. Thanks! The notion of "SemaphoreSlim" is new to me; will try it out when I get back to work tomorrow and report back. About your second 'hack', is it possible to use it with "await query.CountAsync()" and also return a value? – chronodekar Feb 04 '14 at 17:21
  • 1
    Yes, the hack works with return values, i.e., `var count = Task.Run(() => query.CountAsync()).Result`. – Stephen Cleary Feb 04 '14 at 17:40
  • Conceptually, I'm still lost with the whole parallel programming thing. But that's a personal issue I need to study up on. The hack in this answer helped solve my immediate problem at work, so I'm marking it as the answer. (For those who care, my application takes a VERY long time to run, but for its purpose, that's acceptable) – chronodekar Feb 06 '14 at 17:21
  • 1
    Asynchronous != parallel. You may find my [`async` intro](http://blog.stephencleary.com/2012/02/async-and-await.html) helpful. – Stephen Cleary Feb 06 '14 at 18:29
1

if the api method returns an async task, you can get the awaiter and get the result synchronously

    api.DoWorkAsync().GetAwaiter().GetResult();
Lorentz Vedeler
  • 5,101
  • 2
  • 29
  • 40