简体   繁体   中英

Why does my BlockOperation continue after I add it to an OperationQueue?

Apple documentation says that Operations run synchronously. Why then does the code continue to run after an operation is added to a queue?

Here is my code:

let op = BlockOperation(block: { print("Done") })
                        
let qu = OperationQueue()
                        
qu.addOperation(op)

print("after!")

Here is the debug results:

after!

Done

You said:

Apple documentation says that Operations run synchronously. Why then does the code continue to run after an operation is added to a queue?

Your debug output is correct. The BlockOperation will run asynchronously with respect to the thread which added it to the operation queue. The confusing and inconsistent terminology employed by the Operation and OperationQueue documentation does not help the matter (see below).

But, in short, operations added to an operation queue will run asynchronously with respect to the thread which added them to the queue (unless you explicitly wanted to “wait until finished”, ie, you supply true for the second parameter of addOperations(_:waitUntilFinished:) ; but that is an anti-pattern which we simply do not use very often).


I do not know if this is the source of the confusion or not, but there is also a question as to whether the task wrapped by the operation is, itself, synchronous or asynchronous. The Apple documentation refers to these as “non-concurrent” or “concurrent” operations, respectively.

BlockOperation is for “non-concurrent” tasks only (ie, when the block finishes, the BlockOperation is finished). So, if you stumble across any documentation that refers to the synchronous nature of BlockOperation , that is in reference to the synchronous, ie, non-concurrent, nature of the block supplied to the operation, not the broader relationship between the BlockOperation and the thread that added it to the queue. Operations run asynchronously with respect to the thread that added them to the queue (whether the operation, itself, is concurrent or not).

FWIW, if you really were wrapping an inherently asynchronous task (such as a network request) within an operation, that called a “concurrent” operation in Apple's terminology. You would not use BlockOperation for a “concurrent” operation. You would subclass Operation , perform the necessary KVO for “concurrent” operations. (If you really want to go tumbling down that rabbit hole, see https://stackoverflow.com/a/40560463/1271826 or https://stackoverflow.com/a/48104095/1271826 , but this is largely unrelated to the question at hand.)


There is a final notion of “synchronous” vs “asynchronous” within the Operation and OperationQueue documentation. Specifically, the documentation dwells on the terms “asynchronous” and “synchronous” operations in the context of the start method, ie, operations that are not added to a queue, but are just started immediately. If you call start on a “synchronous operation” (rather than adding it to a queue), the calling thread will wait. If you call start an “asynchronous operation”, the calling thread will not wait.

I hate to even bring up this idiosyncratic terminology, but only mention for those stumbling through Apple's documentation. Apple's use of “synchronous” vs “asynchronous” in this section only applies within the context of the start method. Obviously, we (and Apple, elsewhere in their own documentation) often use these terms more generally.


You raised another question:

The synchronous code runs immediately and the thread that calls it waits until the synchronous code finishes. Or is that only if the synchronous code runs on the same thread?

“Synchronous” simply means that the caller will not proceed until the synchronous code finishes.

Not to split hairs, but it makes no assurances that the synchronous code will execute immediately (though it generally will). It just means that the caller will not proceed until the synchronous call finishes. But if, for example, the synchronously dispatched code is added to a queue that is backlogged, it might not start immediately.

The term “synchronous” also makes no assurances that it will run on the same thread or a different one. Sometimes is will run it on the current thread. Sometimes it will simply wait on the current thread while the synchronous task finishes on some other thread. It depends upon the particular situation.

“Synchronous” only means that the caller will wait, with no assurances about when or where the synchronous code will execute. That's it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM