[英]Async tasks execution with dependency
Situation:情况:
I have 2 tasks says T1 & T2 in async background mode.我有 2 个任务在异步后台模式下显示T1和T2 。 T2 depends on T1 and have successBlock which is executes after the completion of the both tasks T1 & T2 . T2依赖于T1并且有successBlock它在两个任务T1和T2完成后执行。
Quick diagram is below for better understanding.为了更好地理解,快速图表如下。
Edit:编辑:
To better understanding the tasks, you can assume T1 and T2 are the API calls which always be going to execute in async mode.为了更好地理解任务,您可以假设 T1 和 T2 是始终以异步模式执行的 API 调用。 I need some output data from T1 to hit T2 API.我需要一些来自 T1 的输出数据来命中 T2 API。 After the completion of the both tasks I need to update UI.完成这两个任务后,我需要更新 UI。
To accomplish this scenario, I have added my first async work in T1 and second work in T2 and dependency of T2 to T1 and successblock have dependency on both tasks.为了完成这个场景,我在T1 中添加了我的第一个异步工作,在T2 中添加了第二个工作,并且T2对T1和 successblock 的依赖依赖于这两个任务。
Code Work代码工作
My Tasks我的任务
class TaskManager { static let shared = TaskManager() func task1Call(complete: @escaping ()->()) { DispatchQueue.global(qos: .background).async { for i in 0...10 { print("~~> Task 1 Executing ..", i) sleep(1) } complete() } } func task2Call(complete: @escaping ()->()) { DispatchQueue.global(qos: .background).async { for i in 0...10 { print("==> Task 2 Executing ..", i) sleep(1) } complete() } } }
Execute Tasks执行任务
class Execution { // Managing tasks with OperationQueue func executeTaskWithOperation() { let t1 = BlockOperation { TaskManager.shared.task1Call { print("Task 1 Completed") } } let t2 = BlockOperation { TaskManager.shared.task2Call { print("Task 2 Completed") } } let successBlock = BlockOperation { print("Tasks Completed") } let oper = OperationQueue() t2.addDependency(t1) successBlock.addDependency(t2) successBlock.addDependency(t1) oper.addOperations([t1, t2, successBlock], waitUntilFinished: true) } } let e = Execution() e.executeTaskWithOperation()
Issue:问题:
Both tasks are executing parallelly and successBlock executes before the completion of task 1 and task 2.两个任务并行执行,且successBlock在任务 1 和任务 2 完成之前执行。
Console Output:控制台输出:
==> Task 2 Executing .. 0
Tasks Completed
~~> Task 1 Executing .. 0
~~> Task 1 Executing .. 1
==> Task 2 Executing .. 1
==> Task 2 Executing .. 2
~~> Task 1 Executing .. 2
==> Task 2 Executing .. 3
~~> Task 1 Executing .. 3
==> Task 2 Executing .. 4
~~> Task 1 Executing .. 4
==> Task 2 Executing .. 5
~~> Task 1 Executing .. 5
==> Task 2 Executing .. 6
~~> Task 1 Executing .. 6
==> Task 2 Executing .. 7
~~> Task 1 Executing .. 7
==> Task 2 Executing .. 8
~~> Task 1 Executing .. 8
==> Task 2 Executing .. 9
~~> Task 1 Executing .. 9
~~> Task 1 Executing .. 10
==> Task 2 Executing .. 10
Task 1 Completed
Task 2 Completed
I unable to figure out what wrong I am doing, even same code work fines when I use sync mode instead of async.我无法弄清楚我在做什么错,当我使用同步模式而不是异步模式时,即使是相同的代码也能正常工作。
Your t1
and t2
are block operations that spawn background threads (which each do some printing and then exit, but it doesn't matter).您的t1
和t2
是产生后台线程的块操作(每个线程都进行一些打印然后退出,但这并不重要)。 Once they finish spawning, they're considered completed.一旦它们完成产卵,它们就被视为已完成。 successBlock
depends on the two background threads being spawned, and then it's done. successBlock
取决于产生的两个后台线程,然后就完成了。 You want the work in the BlockOperation
itself:您想要BlockOperation
本身的工作:
class Execution {
// Managing tasks with OperationQueue
func executeTaskWithOperation() {
let t1 = BlockOperation {
for i in 0...10 {
print("~~> Task 1 Executing ..", i)
sleep(1)
}
print("Task 1 completed")
}
let t2 = BlockOperation {
for i in 0...10 {
print("==> Task 2 Executing ..", i)
sleep(1)
}
print("Task 2 Completed")
}
let successBlock = BlockOperation {
print("Tasks Completed")
}
let oper = OperationQueue()
t2.addDependency(t1) // Remove this to see concurrent exec of t1 and t2
successBlock.addDependency(t2)
successBlock.addDependency(t1)
oper.addOperations([t1, t2, successBlock], waitUntilFinished: true)
}
}
let e = Execution()
e.executeTaskWithOperation()
Edit: For execution on a background thread, override Operation
.编辑:要在后台线程上执行,请覆盖Operation
。
class AsyncOp: Operation {
let task: String
var running = false
var done = false
init(_ task: String) {
self.task = task
}
override var isAsynchronous: Bool { true }
override var isExecuting: Bool {
get { running }
set {
willChangeValue(forKey: "isExecuting")
running = newValue
didChangeValue(forKey: "isExecuting")
}
}
override var isFinished: Bool {
get { done }
set {
willChangeValue(forKey: "isFinished")
done = newValue
didChangeValue(forKey: "isFinished")
}
}
override func main() {
DispatchQueue.global(qos: .background).async {
self.isExecuting = true
for i in 0...10 {
print("\(self.task) Executing ..", i)
sleep(1)
}
print("Done")
self.isExecuting = false
self.isFinished = true
}
}
override func start() {
print("\(task) starting")
main()
}
}
class Execution {
// Managing tasks with OperationQueue
func executeTaskWithOperation() {
let t1 = AsyncOp("task1")
let t2 = AsyncOp("task2")
let successBlock = BlockOperation {
print("Tasks Completed")
}
let oper = OperationQueue()
t2.addDependency(t1)
successBlock.addDependency(t2)
successBlock.addDependency(t1)
oper.addOperations([t1, t2, successBlock], waitUntilFinished: true)
}
}
let e = Execution()
e.executeTaskWithOperation()
After Joshua's comment , I able to conclude the answer.在约书亚的评论之后,我能够得出答案。
Execution changed from OperationQueue
to DispatchGroup
and DispatchSemaphore
.执行从OperationQueue
更改为DispatchGroup
和DispatchSemaphore
。
DispatchGroup : It makes sure both task tasks are done and then it calls notify
block. DispatchGroup :它确保完成两个任务任务,然后调用notify
块。
DispatchSemaphore : It holds the async resource with wait command until we wont send the signal command ie we are saying to semaphore to hold yourself until the task1 is not completed. DispatchSemaphore :它使用等待命令保存异步资源,直到我们不会发送信号命令,即我们告诉信号量保持自己直到 task1 未完成。
Sample code of tasks.任务示例代码。
class Execution {
// Managing tasks with DispatchGroup
func executeTaskWithGroup() {
let groups = DispatchGroup()
let semaphore = DispatchSemaphore(value: 1)
groups.enter()
semaphore.wait()
TaskManager.shared.task1Call {
groups.leave()
semaphore.signal()
}
groups.enter()
TaskManager.shared.task2Call {
groups.leave()
}
groups.notify(queue: DispatchQueue.global(qos: .background)) {
print("Tasks Completed")
}
}
}
To execute command all we need to do is.要执行命令,我们需要做的就是。
let e = Execution()
e.executeTaskWithGroup()
But above code is executed in the main thread and block the UI.但是上面的代码在主线程中执行并阻塞UI。 To prevent this you need to call above piece of code in background queue like below.为了防止这种情况,您需要在后台队列中调用上面的代码,如下所示。
let queue = DispatchQueue.init(label: "MyQueue", qos: .background, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)
queue.async {
let e = Execution()
e.executeTaskWithGroup()
}
Now everything works fine as per my needed.现在一切正常,按照我的需要。
AddOn添加在
In case, if someone requirement is to call multiple API along with the above scenario then add your tasks in async in the queue.如果有人要求在上述场景中调用多个 API,则将您的任务异步添加到队列中。
let queue = DispatchQueue.init(label: "MyQueue", qos: .background, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)
queue.async {
let e1 = Execution()
e1.executeTaskWithGroup()
}
queue.async {
let e2 = Execution()
e2.executeTaskWithGroup()
}
Now both e1 and e2 executes parallelly without blocking main thread.现在e1和e2并行执行而不会阻塞主线程。
References :参考 :
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.