title: Unreal Engine 4 - How to avoid blocking game thread when saving file to storage
body: <p>I'm working on a gearvr app and trying to download an mp4 (aprox 250mb) and save it to the device. </p>
  
  <p>It seems the save operation blocks the game thread, which causes the rendering to freeze for a few seconds, while the gearvr IMU remains active. The result is that the game freezes and you basically end up being able to look around a frozen quad :/</p>
  
  <p>My download and save code is:</p>
  
  <pre><code>request-&gt;OnProcessRequestComplete().BindLambda([&amp;](FHttpRequestPtr request, FHttpResponsePtr response, bool success) {
          if (!success) {
              return;
          }
  
          TArray&lt;uint8&gt; data = response-&gt;GetContent();
          FString path = FPaths::Combine(FPaths::GamePersistentDownloadDir(), "video.mp4");
          FBufferArchive archive;
          archive &lt;&lt; data;
  
          success = FFileHelper::SaveArrayToFile(archive, *path);
  
          if (success) {
              UGameplayStatics::OpenLevel(GetWorld(), "Player");
          }
      });
  </code></pre>
  
  <p>Since the downloading operation itself does not seem to be the one blocking the UI, I assume it would be either the insertion operator <code>archive &lt;&lt; data</code> or <code>SaveArrayToFile</code>. So I tried doing both operations on a separate thread, like so:</p>
  
  <pre><code>ACard::ACard() {
      PrimaryActorTick.bCanEverTick = true;
  
      // ...
  
      request-&gt;OnProcessRequestComplete().BindLambda([&amp;](FHttpRequestPtr request, FHttpResponsePtr response, bool success) {
          GEngine-&gt;AddOnScreenDebugMessage(-1, 2.f,
              success ? FColor::Green : FColor::Red,
              success ? TEXT("download successful") : TEXT("download failed"));
  
          if (!success) {
              return;
          }
  
          task = Task::dispatch([response]() {
              FBufferArchive archive;
              TArray&lt;uint8&gt; data = response-&gt;GetContent();
              archive &lt;&lt; data;
  
              FString path = FPaths::Combine(FPaths::GamePersistentDownloadDir(), "video.mp4");
              FFileHelper::SaveArrayToFile(archive, *path);
          });
  
          SetActorTickEnabled(true);
      });
  }
  
  void ACard::BeginPlay() {
      Super::BeginPlay();
      SetActorTickEnabled(false);
  }
  
  void ACard::Tick( float DeltaTime ) {
      Super::Tick( DeltaTime );
  
      if (task &amp;&amp; task-&gt;complete) {
          SetActorTickEnabled(false);
          UGameplayStatics::OpenLevel(GetWorld(), "Player");
      }
  }
  </code></pre>
  
  <p>Where <code>Task</code> is defined like so:</p>
  
  <pre><code>class  Task : public FRunnable {
  
  private:
      TFunction&lt;void()&gt; task;
      FRunnableThread* thread;
  
  public:
      bool complete{ false };
  
      static Task* dispatch(TFunction&lt;void()&gt; task) {
          auto newInstance = new Task(task);
  
          newInstance-&gt;thread = FRunnableThread::Create(
              newInstance,
              TEXT(""),
              0,
              TPri_BelowNormal
          );
  
          return newInstance;
      }
  
      Task(TFunction&lt;void()&gt; task) : task(task) {}
      bool Init() override { return true; }
      void Stop() override {}
  
      uint32 Run() override {
          task();
          complete = true;
          return 0;
      }
  };
  </code></pre>
  
  <p>But the above seems to make no difference: Saving the file still blocks the UI for about 3secs.
  So my question is: how should I be saving the file to storage without blocking the game itself?</p>
  
  <p>UPDATE:</p>
  
  <p>This issue is still not resolved. Following the advice in one of the comments below, I added logs to check that the code does indeed execute on separate threads and it does. The logs are consistent with the actions:</p>
  
  <ol>
  <li>Dispatch save task from game thread.</li>
  <li>execute task (save) in background thread.</li>
  <li>dispatch new task to load the next level from background thread.</li>
  <li>execute new task (load next level) from game thread.</li>
  </ol>
  
  <p>Yet the UI thread still blocks.</p>
  
  <pre><code>01 - 18 19:59 : 10.404 18059 18075 D UE4 : LogTemp:Warning: Dispatch TASK : tID 18075 | is game ? 1
  01 - 18 19 : 59 : 10.404 18059 18075 D UE4 : [2017.01.19 - 00.59.10:415][-8608252]LogTemp : Warning : Dispatch TASK : tID 18075 | is game ? 1
  01 - 18 19 : 59 : 10.414 18059 18259 D UE4 : LogTemp:Warning: Execute TASK : tID 18259 | is game ? 0
  01 - 18 19 : 59 : 10.414 18059 18075 D UE4 : [2017.01.19 - 00.59.10:419][-8608252]LogTemp : Warning : Execute TASK : tID 18259 | is game ? 0
  01 - 18 19 : 59 : 10.524 18059 18140 I OVR : PhoneManagerThread - phone running!nfds = 1
  01 - 18 19 : 59 : 10.524 18059 18259 D UE4 : LogTemp:Warning: Dispatch TASK : tID 18259 | is game ? 0
  01 - 18 19 : 59 : 10.524 18059 18075 D UE4 : [2017.01.19 - 00.59.10:536][-8608252]LogTemp : Warning : Dispatch TASK : tID 18259 | is game ? 0
  01 - 18 19 : 59 : 11.064 18059 18075 D UE4 : LogTemp:Warning: Execute TASK : tID 18075 | is game ? 1
  01 - 18 19 : 59 : 11.064 18059 18075 D UE4 : [2017.01.19 - 00.59.11:072][-8608252]LogTemp : Warning : Execute TASK : tID 18075 | is game ? 1
  </code></pre>