Does 'perform(schedule: .immediate)' guarantee serial execution?

If I have two consecutive calls like to perform(schedule: .immediate) like so:

func doSomething() async {
   await self.perform(schedule: .immediate) {
       // add log event 1 to data store
   }
   await self.perform(schedule: .immediate) {
       // add log event 2 to data store
   }
}

Can I be guaranteed that the block for log event 1 will happen after log event 2?

"log event" here is just an example, so please ignore things like storing date, etc.

Looking at the documentation here:

https://developer.apple.com/documentation/coredata/nsmanagedobjectcontext/perform(schedule:_:)

It's a little unclear whether any such guarantee is in place. However, given that the function returns the value from the block, it seems like I should be able to expect event 1 will always be executed before event 2 regardless of the schedule parameter?

Answered by DTS Engineer in 876349022

Every NSManagedObjectContext has a private serial dispatch queue. perform(schedule: .immediate) runs the block immediately, if the code is currently running in the dispatch queue of the managed object context. Otherwise, it does perform(schedule: .enqueue), which enqueues the block to the context's dispatch queue.

In your code snippet, you use await to serialize the two performs, and so for every single doSomething, the system guarantees that the first block ("add log event 1") is done BEFORE the second one ("add log event 2") is started.

Maybe worth mentioning, like other async functions, doSomething can be re-entered. Assuming that doSomething is called twice, it's possible that the first block of the second doSomething is enqueued before the second block of the first doSomething is.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Accepted Answer

Every NSManagedObjectContext has a private serial dispatch queue. perform(schedule: .immediate) runs the block immediately, if the code is currently running in the dispatch queue of the managed object context. Otherwise, it does perform(schedule: .enqueue), which enqueues the block to the context's dispatch queue.

In your code snippet, you use await to serialize the two performs, and so for every single doSomething, the system guarantees that the first block ("add log event 1") is done BEFORE the second one ("add log event 2") is started.

Maybe worth mentioning, like other async functions, doSomething can be re-entered. Assuming that doSomething is called twice, it's possible that the first block of the second doSomething is enqueued before the second block of the first doSomething is.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Does 'perform(schedule: .immediate)' guarantee serial execution?
 
 
Q