# Async/Await: is it possible to start a Task on @MainActor synchronously?

**URL:** <https://forums.swift.org/t/async-await-is-it-possible-to-start-a-task-on-mainactor-synchronously/52862>\
**Category:** Using Swift\
**Tags:** asyncawait\
**Created:** [October 16, 2021, 9:43am UTC](https://forums.swift.org/t/async-await-is-it-possible-to-start-a-task-on-mainactor-synchronously/52862 "2021-10-16T09:43:41Z")\
**Posts on this page:** 1\
**Showing post:** 23

<div class="post-metadata">

**Author:** ![kabiroberai](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kabiroberai/32/28072_2.png) [@kabiroberai](https://forums.swift.org/u/kabiroberai)\
**Post date:** [November 24, 2023, 7:33am UTC](https://forums.swift.org/t/async-await-is-it-possible-to-start-a-task-on-mainactor-synchronously/52862/23 "2023-11-24T07:33:32Z")

</div>

I'd usually avoid reviving an old thread but I wanted to share a solution here given that I'm probably not the only one who found this page while searching the web for this problem.

As several people pointed out, you can't _always_ run an async task synchronously because it may suspend, during which time blocking the synchronous thread would violate the forward progress invariant. However it IS legal within the rules of Concurrency to start a task synchronously; that is, to execute the first `Job` immediately, assuming you're already on the correct executor. The only hurdle is that by default, `Task.init` uses the global executor to enqueue new `Job`s, which always causes the job to run on the next tick (NB: not 100% sure of the terminology here so if someone more knowledgeable finds that I mixed up a few terms please correct me.) Eventually Swift will probably have a kosher solution for solving this in the form of Task Executors:

> [@\[Pitch\] Task Executor Preference](https://forums.swift.org/t/pitch-task-executor-preference/68191):
>
> Hello everyone, We'd like to share a proposal that've been working towards for a while now. Read the full proposal here: [SE-NNNN: Task Executor Preference](https://github.com/ktoso/swift-evolution/blob/wip-task-executors/proposals/NNNN-task-executor-preference.md). (In case of small typos, please comment on the [pull request](https://github.com/apple/swift-evolution/pull/2187/)) The proposal introduces task executors which enable a structured task hierarchy to have a "preference" where all of its tasks should execute. In short, task executors allow setting an executor that will be used by the task. The task is enqueued on ("starts on") that executor, …

~~Luckily the Swift runtime already includes a tool to override the global enqueue implementation: [https://github.com/apple/swift/blob/98e65d015979c7b5a58a6ecf2d8598a6f7c85794/stdlib/public/Concurrency/GlobalExecutor.cpp#L107](https://github.com/apple/swift/blob/98e65d015979c7b5a58a6ecf2d8598a6f7c85794/stdlib/public/Concurrency/GlobalExecutor.cpp#L107)~~

EDIT: In the meanwhile, as it so happens, there's already SPI that does exactly this for us, though the usual warnings around private API usage apply.

> <https://github.com/swiftlang/swift/blob/98e65d015979c7b5a58a6ecf2d8598a6f7c85794/stdlib/public/Concurrency/Task.swift#L250-L294>

With some tinkering, you can build something that utilizes this: see [Run tasks synchronously on the Main Actor: https://forums.swift.org/t/async-await-is-it-possible-to-start-a-task-on-mainactor-synchronously/52862/23 · GitHub](https://gist.github.com/kabiroberai/89b370dcaee54a2f075fba7989b0b799).

And accordingly, the original problem can be solved:

```swift
func calledOnTheMainThread() /* non async */ {
  let task = Task.startOnMainActor {
    print("started")
    try? await Task.sleep(for: .seconds(5))
    print("ended")
  }
  // "started" is printed synchronously!
}

```

---

_[View the full topic](https://forums.swift.org/t/async-await-is-it-possible-to-start-a-task-on-mainactor-synchronously/52862)._
