Concurrency Flashcards

1
Q

Should I use GCD or Operations?

A

GCD tends to be simpler to work with for simple tasks you just need to execute and forget.

Operations provide much more functionality when you need to keep track of a job or maintain the ability to cancel it.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Serial and concurrent queues

A

Serial queues only have a single thread associated with them and thus only allow a single task to be executed at any given time.

A concurrent queue, on the other hand, is able to utilize as many threads as the system has resources for. Threads will be created and released as necessary on a concurrent queue.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Synchronous and asynchronous tasks

A

When running a task synchronously, your app will wait and block the current run loop until execution finishes before moving on to the next task.

Alternatively, a task that is run asynchronously will start, but return execution to your app immediately. This way, the app is free to run other tasks while the first one is executing.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Operations

A

Has states

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

BlockOperation

A

BlockOperation subclasses Operation for you and manages the concurrent execution of one or more closures on the default global queue

Block operations run concurrently. If you need them to run serially, you’ll need to setup a dispatch queue instead.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Quality of service queues

A

◦ .userInteractive

◦ .userInitiated

◦ .utility

◦ .background

◦ .default and .unspecified

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Global queues

A

Global queues are always concurrent and first-in, first-out.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

When you add a higher task to global queue ->

A

You can specify a QoS yourself, but as soon as you’ll add a task with a higher QoS, your queue’s QoS service will be increased to match it.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

You never want to execute something synchronously against

A

the main queue

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

When you want a DispatchGroup?

A

when you want to track the completion of a group of tasks.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

DispatchGroup features

A

notify(queue:) {}

Synchronous waiting vs enter and leave methods

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

.notify(queue:) {} feature in DispatchGroup

A

DispatchGroups provide a notify(queue:) method, which you can use to be notified as soon as every job submitted has finished.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Synchronous waiting vs enter and leave methods in DispatchGroup

A

Sync waiting blocks the current thread

Every time you enter, the count goes up by 1. When you leave, the count goes down by 1

queue.dispatch(group: group) {
// count is 1
group.enter()
// count is 2
someAsyncMethod {
defer { group.leave() }
// Perform your work here,
// count goes back to 1 once complete
} }

you will usually want to use a defer statement, as shown above, so that, no matter how you exit the closure, the group.leave() code executes. regardless of how it exits, you’ve got to tell the dispatch group that the task has completed

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

When you want use semaphores?

A

you may wish to limit how many tasks happen at once.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

How to use semaphores?

A

◦ semaphore.wait()

◦ defer { semaphore.signal() }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Asynchronous doesnʼt mean concurrent

A

While the difference seems subtle at first, just because your tasks are asynchronous doesn’t mean they will run concurrently. You’re actually able to submit asynchronous tasks to either a serial queue or a concurrent queue. Being synchronous or asynchronous simply identifies whether or not the queue on which you’re running the task must wait for the task to complete before it can spawn the next task.

a task being synchronous or not speaks to the source of the task. Being serial or concurrent speaks to the destination of the task.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

you should never find yourself needing to create a thread explicitly.

A

The OS will handle all thread creation for you using higher abstractions.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

If you find yourself calling the sync method, instead of the async method,

A

think once or twice whether that’s really what you should be doing.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Concurrency Problems

A

Deadlock
Race conditions
Priority inversion

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

How to avoid Race conditions?

A

Use serial queue or use Thread barrier

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Thread barrier

A

.async(flags: .barrier)

Once the barrier hits, the queue pretends that it’s serial and only the barrier task can run until completion. Once it completes, all tasks that were submitted after the barrier task can again run concurrently.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Use serial queue to avoid Race conditions

A
private let threadSafeCountQueue = DispatchQueue(label: "...") private var _count = 0
public var count: Int {
get {
return threadSafeCountQueue.sync {
_count }
} set {
threadSafeCountQueue.sync {
_count = newValue
}
} }
23
Q

Deadlock

A

as you are both waiting on another task that can never complete.

Accidentally calling sync against the current dispatch queue is the most common occurrence of this that you’ll run into.

Very rare

24
Q

Priority inversion

A

Priority inversion occurs when a queue with a lower quality of service is given higher system priority than a queue with a higher quality of service, or QoS. If you’ve been playing around with submitting tasks to queues, you’ve probably noticed a constructor to async, which takes a qos parameter.

25
Q

How to avoid Priority inversion problem?

A

If you need a higher quality of service, use a different queue!

26
Q

How Priority inversion problem happens?

A

When I send .userInteractive tasks to lower quality queue and all tasks from this queue has high priority now

or

when I use semaphore and put high quality queue the last

27
Q

Tasks in a BlockOperation run

A

concurrently. If you need them to run serially, submit them to a private DispatchQueue or set up dependencies.

28
Q

BlockOperation manages one closure or group?

A

It manages a group of closures

29
Q

OperationQueue allows you to add work in three separate ways:

A

Pass an Operation.
Pass a closure.
Pass an array of Operations.

30
Q

Do I should call .start() manually on Operation?

A

Generally, you shouldn’t call start manually, unless you really know what you’re doing!

31
Q

How BlockOperation closures run?

A

Concurrently @escaping

32
Q

OperationQueue management

A

The operation queue executes operations that are ready, according to quality of service values and any dependencies the operation has. Once you’ve added an Operation to the queue, it will run until it has completed or been canceled. You’ll learn about dependencies and canceling operations in future chapters.
Once you’ve added an Operation to an OperationQueue, you can’t add that same Operation to any other OperationQueue. Operation instances are once and done tasks, which is why you make them into subclasses so that you can execute them multiple times, if necessary.

33
Q

Waiting for OperationQueue completion

A

waitUntilAllOperationsAreFinished

Calling it blocks the current thread, meaning that you must never call this method on the main UI thread.

If you find yourself needing this method, then you should set up a private serial DispatchQueue wherein you can safely call this blocking method. If you don’t need to wait for all operations to complete, but just a set of operations, then you can, instead, use the addOperations(_:waitUntilFinished:) method on OperationQueue.

34
Q

Pausing the OperationQueue

A

You can pause the dispatch queue by setting the isSuspended property to true. In-flight operations will continue to run but newly added operations will not be scheduled until you change isSuspended back to false

35
Q

Maximum number of operations in OperationQueue

A

Sometimes you’ll want to limit the number of operations which are running at a single time. By default, the dispatch queue will run as many jobs as your device is capable of handling at once. If you wish to limit that number, simply set the maxConcurrentOperationCount property on the dispatch queue. If you set the maxConcurrentOperationCount to 1, then you’ve effectively created a serial queue.

36
Q

Underlying DispatchQueue

A

Before you add any operations to an OperationQueue, you can specify an existing DispatchQueue as the underlyingQueue. If you do so, keep in mind that the quality of service of the dispatch queue will override any value you set for the operation queue’s quality of service.

Note: Do not specify the main queue as the underlying queue!

37
Q

If you need make a outlet public

A

While you could make the outlet property public and call the methods directly, it’s suggested to not expose UI elements and outlets to avoid leaking UIKit-specific logic to higher layers of abstraction.

38
Q

Callback that can be run on the main thread

A

the main thread
It’s very important that you document the fact that your completion handler is being run on the main UI thread instead of the operation queue’s provided thread.
The end user needs to know you’re switching threads on them so they don’t do something that could impact the application

39
Q

Modular design in operation

A

One task per operation

40
Q

Specifying dependencies

A

In this way you can avoid pyramid of doom with GCD

41
Q

Watching out for deadlock

A

Watch out of loops in dependencies

42
Q

Passing data between operations

A

using protocols

set data that you want to pass between operation as protocol property and conform this protocol by all operation classes

43
Q

Operation dependencies setup

A

Add dependencies
Handle op.completionHandler = {} OR override this handler with closure calling it on main.async if you want to handle it on main queue x
Add operations to queue

44
Q

Canceling operations

A

“There’s nothing magical about how canceling an operation works. If you send a request to an operation to stop running, then the isCancelled computed property will return true. Nothing else happens automatically!”

45
Q

The one and only change you can make, once it’s been added to the queue,

A

is to call the cancel method of Operation

46
Q

Canceling operation methods

A

Cancel and cancelAllOperations

47
Q

Canceling a running operation in table view

A

store operations in array in VC and call cancel on them when they are invisible

48
Q

NSManagedObjectContext is not thread safe

explain

A

There are two methods available on the NSManagedObjectContext class to help with concurrency:
perform(:) async
performAndWait(
:) sync
What both methods do is ensure that whatever action you pass to the closure is executed on the same queue that created the context. Notice how it’ not “on the main thread.” You might create your own context on another queue. These methods thus ensure that you are always executing against the proper thread and don’t crash at runtime

49
Q

NSAsynchronousFetchRequest

A

Construct the fetch request as you normally would but then pass that fetch request as the first parameter to the constructor of NSAsynchronousFetchRequest. The second parameter is a closure to be executed when the fetch completes. The closure takes a single argument of type NSAsynchronousFetchResult.

50
Q

If two separate threads both need access to the same NSManagedObject

A

“you must pass the NSManagedObjectId instead of the actual NSManagedObject

51
Q

Using ConcurrencyDebug

A

To help protect yourself from sharing an NSManagedObject across threads, you can enable a runtime debug flag by editing the project’ scheme and passing a runtime argument.

Add -com.apple.CoreData.ConcurrencyDebug 1 to your app’s scheme to catch calling Core Data methods on the wrong thread in the debugger.

52
Q

What you cannot do with NSManagedObject?

A

Pass it to another thread

53
Q

Thread sanitizer

A

The Thread Sanitizer, commonly referred to as TSan, is a tool Apple provides as part of the LLVM compiler. TSan allows you to identify when multiple threads attempt to access the same memory without providing proper access synchronization.
Note: TSan is only supported when running on the simulator.