title: Understanding single-threaded nature of Orleans grains
body: <p>I have the following code snippet of a client and a grain in Orleans. <strong>(Although the recommended way to develop in Orleans is to await Tasks, the following code doesn't await at some points purely for experimentation purposes)</strong> </p>
  
  <pre><code>// client code
  while(true)
  {
      Console.WriteLine("Client giving another request");   
      double temperature = random.NextDouble() * 40;   
      var grain = client.GetGrain&lt;ITemperatureSensorGrain&gt;(500);
      Task t = sensor.SubmitTemperatureAsync((float)temperature);
      Console.WriteLine("Client Task Status - "+t.Status);
      await Task.Delay(5000);
  }
  
  // ITemperatureSensorGrain code
  public async Task SubmitTemperatureAsync(float temperature)
  {
     long grainId = this.GetPrimaryKeyLong();
     Console.WriteLine($"{grainId} outer received temperature: {temperature}");
  
     Task x = SubmitTemp(temperature); // SubmitTemp() is another function in the same grain
     x.Ignore();
     Console.WriteLine($"{grainId} outer received temperature: {temperature} exiting");
  }
  
  public async Task SubmitTemp(float temp)
  {
      for(int i=0; i&lt;1000; i++)
      {
         Console.WriteLine($"Internal function getting awaiting task {i}");
         await Task.Delay(1000);
      }
  }
  </code></pre>
  
  <p>The output when I run the above code is the following:</p>
  
  <pre><code>Client giving another request
  Client Task Status - WaitingForActivation
  500 outer received temperature: 23.79668
  Internal function getting awaiting task 0
  500 outer received temperature: 23.79668 exiting
  Internal function getting awaiting task 1
  Internal function getting awaiting task 2
  Internal function getting awaiting task 3
  Internal function getting awaiting task 4
  Client giving another request
  Client Task Status - WaitingForActivation
  500 outer received temperature: 39.0514
  Internal function getting awaiting task 0  &lt;------- from second call to SubmitTemp
  500 outer received temperature: 39.0514 exiting
  Internal function getting awaiting task 5  &lt;------- from first call to SubmitTemp
  Internal function getting awaiting task 1
  Internal function getting awaiting task 6
  Internal function getting awaiting task 2
  Internal function getting awaiting task 7
  Internal function getting awaiting task 3
  Internal function getting awaiting task 8
  Internal function getting awaiting task 4
  Internal function getting awaiting task 9
  </code></pre>
  
  <p>The output makes sense from the perspective of a normal .Net application. If I can take help from <a href="https://stackoverflow.com/questions/51567128/result-of-task-invocation-on-a-grain-in-orleans">this stackoverflow post</a>, what is happening here is that:</p>
  
  <ol>
  <li>Client makes a call to <code>ITemperatureSendorGrain</code> and proceeds ahead. When the <code>await</code> is hit, the client thread is returned to the threadpool. </li>
  <li><code>SubmitTemperatureAsync</code> receives the request and calls a local async function <code>SubmitTemp</code>.</li>
  <li><code>SubmitTemp</code> prints statement corresponding to i=0 after which point it hits await. Await causes the rest of the <code>for loop</code> to be scheduled as a continuation of the awaitable (Task.Delay) and the control returns to the calling function <code>SubmitTemperatureAsync</code>. Note here that the thread isn't returned to the threadpool when it encounters await in <code>SubmitTemp</code> function. The thread control is actually returned to the calling function <code>SubmitTemperatureAsync</code>. So, a <code>turn</code>, as defined in Orleans docs, ends when the top level method encounters an await. When a turn ends, the thread is returned to the threadpool. </li>
  <li>The calling function doesn't wait for the task to finish and exits.</li>
  <li>When the awaitable in <code>SubmitTemp</code> returns after 1s, it gets a thread from the threadpool and schedules the rest of the <code>for loop</code> on it.</li>
  <li>When the awaitable in client code returns, it makes another call to the same grain and another round of <code>for loop</code> is scheduled corresponding to the second call to <code>SubmitTemp</code>.</li>
  </ol>
  
  <p><strong>My first question</strong> is have I correctly described what's happening in the code, especially about the thread not being returned to the thread pool when await is hit in the function <code>SubmitTemp</code>.</p>
  
  <hr>
  
  <p>According to single-threaded nature of grains, at any time only one thread will be executing a grain's code. Also, once a request to a grain begins execution, it will be completed fully before the next request is taken up (called <code>chunk based execution</code> in the Orleans docs). On a high-level, this is true for the above code because the next call to <code>SubmitTemperatureAsync</code> will happen only when the current call to the method exits. </p>
  
  <p>However, <code>SubmitTemp</code> was actually a sub-function of <code>SubmitTemperatureAsync</code>. Although <code>SubmitTemperatureAsync</code> exited, <code>SubmitTemp</code> is still executing and while it does that, Orleans allowed another call to <code>SubmitTemperatureAsync</code> to execute. Doesn't this violate the single-threaded nature of Orleans grain <strong>is my second question</strong>?</p>
  
  <hr>
  
  <p>Consider that <code>SubmitTemp</code> in its <code>for loop</code> needs to access some data members of the grain class. So, the <code>ExecutionContext</code> will be captured when await is encountered and when <code>Task.Delay(1000)</code> returns, the captured <code>ExecutionContext</code> will be passed to the scheduling of the remainder <code>for loop</code> on a thread. Because <code>ExecutionContext</code> is passed, the remainder <code>for loop</code> will be able to access the data members in spite of running on a different thread. This is something which happens in any normal .Net asynchronous application.</p>
  
  <p><strong>My third question</strong> is about <code>SynchronizationContext</code>. I did a cursory search in the Orleans repository but couldn't find any implementation of <code>SynchronizationContext.Post()</code>, which leads me to believe that no <code>SynchronizationContext</code> is required to run Orleans methods. Can anyone confirm this? If this isn't true, and a <code>SynchronizationContext</code> is required, wouldn't the parallel execution of the various invocations of <code>SubmitTemp</code> (as shown in the above code), run the risk of ending in a deadlock (if someone holds on to the <code>SynchronizationContext</code> and doesn't release it)?</p>