0

I am connecting to a REST API and calling a number of end points to get different objects. I create a RestService<T> for each type I want to download:

RestService<Agent> agentService = new RestService<Agent>(auth, new AgentApi());
RestService<Ticket> ticketService = new RestService<Ticket>(auth, new TicketApi());
RestService<Company> companyService = new RestService<Company>(auth, new CompanyApi());
RestService<Contact> contactService = new RestService<Contact>(auth, new ContactApi());

For each RestService<T> I then call GetAll() to call the REST API and get the results:

RestResult<Agent> agentResults = agentService.GetAll();
RestResult<Company> companyResults = companyService.GetAll();
RestResult<Contact> contactResults = contactService.GetAll();
RestResult<Ticket> ticketResults = ticketService.GetAll();

Behind the scenes GetAll() makes a number of HttpWebRequest resquests.

So what I am thinking is to somehow call the 4 GetAll() calls in parallel as in theory I can make multiple requests to the REST API rather than one after the other.

One idea I had was:

RestResult<Agent> agentResults;
RestResult<Company> companyResults;
RestResult<Contact> contactResults;
RestResult<Ticket> ticketResults;

Parallel.Invoke(
    () => agentResults = agentService.GetAll(),
    () => companyResults = companyService.GetAll(),
    () => contactResults = contactService.GetAll(),
    () => ticketResults = ticketService.GetAll()
);

But it looks like the variables are never initialized.

Any suggestions about how to approach this?

moose56
  • 109
  • 1
  • 9
  • What does "it looks like" mean? Are they still `null`? If so, are you sure that the `GetAll()` methods returned something else? – René Vogt Jun 16 '16 at 10:32
  • Sorry, what I meant was I get a compile error saying the variables are unassigned when I try and use them later on. – moose56 Jun 16 '16 at 10:39

2 Answers2

2

You compiler warns you that the variables are not initialized because the compiler does not understand the semantics of Parallel.Invoke().

So the only thing the compiler knows is that you pass some lambdas to that function. But it cannot infer when they will be executed. The compiler does not know that Parallel.Invoke() only returns when all Actions have completed. And it especially does not know that your lambdas are initializing the variables.

So from the point of view of the compiler, even after Parallel.Invoke() you did not yet assign any values to your variables.

The easiest solution is to simply initalize them manually with default values (null):

RestResult<Agent> agentResults = null;
RestResult<Company> companyResults = null;
RestResult<Contact> contactResults = null;
RestResult<Ticket> ticketResults = null;

Parallel.Invoke(
    () => agentResults = agentService.GetAll(Epoch),
    () => companyResults = companyService.GetAll(Epoch),
    () => contactResults = contactService.GetAll(Epoch),
    () => ticketResults = ticketService.GetAll(Epoch)
);
René Vogt
  • 43,056
  • 14
  • 77
  • 99
1

Have a look at this questions, seems like the same problem you are having. Parallel.Invoke does not seem to wait for async operations. Instead use Task.WhenAll to wait for all tasks to complete: Parallel.Invoke does not wait for async methods to complete

RestResult<Agent> agentResults;
RestResult<Company> companyResults;
RestResult<Contact> contactResults;
RestResult<Ticket> ticketResults;

var t1 = Task.Run(() => agentResults = agentService.GetAll(Epoch))
var t2 = Task.Run(() => companyResults = companyService.GetAll(Epoch));
var t3 = Task.Run(() => contactResults = contactService.GetAll(Epoch));
var t4 = Taks.Run(() => ticketResults = ticketService.GetAll(Epoch));

await Task.WhenAll(t1,t2,t3,t4);
//results should be filled here
Community
  • 1
  • 1
Sander Aernouts
  • 959
  • 4
  • 16
  • Don't think that's the reason, the lambdas OP is passing to `Parallel.Invoke()` are _not_ `async`. Even if `GetAll` returned a `Task`, this should be assigned to the variables. And according to documentation `Parallel.Invoke` only returns if all `Action`s have been completed. – René Vogt Jun 16 '16 at 10:38
  • Thanks, but I get a compile error saying the variables are unassigned when I try and use them later on after the await. – moose56 Jun 16 '16 at 10:40
  • Sorry that was just quickly from the top of my head converting your code to the snippet, you could assign them with 'null' as you did in your own example, I overlooked this. It would probably be nicer to return the result in the lambda expression and capture the Tasks results. But, as René pointed out, I assumed your operations where async and that this was causing the issue. – Sander Aernouts Jun 16 '16 at 11:15