DispatchWorkItem与DispatchGroup差异及cancel方法对线程的影响解析
Swift中DispatchWorkItem、DispatchGroup的区别及cancel操作解析
你的代码示例
func run() { // create a work item with the custom code timeoutWorkItem = DispatchWorkItem { // Insert your code here var retryNum: Int = 0 var doRetry: Bool = true while (doRetry) { Thread.sleep(forTimeInterval: TimeInterval(self.mTimeoutMilliSec)) // If we are here then it means the last send did not receive a response before // timing out. Write with no timeout or num retries so we don't spawn another // ResponseTimeoutQueue. retryNum += 1 if (retryNum <= self.mNumRetries) { SessionController.sharedController.invokeWriteData(responseMsgId: self.mResponseMsgId, bytes: self.mMsgOut) } else { doRetry = false } } // Notify the handler. NotificationCenter.default.post(name: .timeOutMessage, object: -1) } //Create dispatch group let dispatchGroup = DispatchGroup() // execute the workItem with dispatchGroup DispatchQueue.global().async(group: dispatchGroup, execute: timeoutWorkItem!) //Handle code after the completion of global queue dispatchGroup.notify(queue: DispatchQueue.global()) { print("global queue execution completed") } //when the App goes to background cancel the workItem timeoutWorkItem?.cancel() }
DispatchWorkItem 和 DispatchGroup 的区别
- DispatchWorkItem:是封装了可执行代码的"任务容器",可以提交到任意GCD队列执行,支持标记取消、设置优先级、监听完成状态。核心是打包任务逻辑,方便单独管理任务的生命周期。
- DispatchGroup:是任务同步工具,用来跟踪一组异步任务的执行进度。你可以把多个任务加入同一个group,通过
notify或wait等待所有任务完成,核心作用是实现多任务的同步,本身不包含任务逻辑。
核心问题解答
1. 调用timeoutWorkItem?.cancel()会不会取消当前线程?
不会。cancel()只是给DispatchWorkItem标记一个"已取消"的状态,不会直接终止正在运行的线程。线程由GCD队列管理,任务取消后,线程会继续处理队列中的其他任务或被系统回收,不会被强制终止。
2. 代码里的Thread.sleep会取消哪个线程?
Thread.sleep是让当前执行代码块的线程进入休眠。如果timeoutWorkItem已经开始执行,调用cancel()后:
- 线程会完成当前的
Thread.sleep休眠(不会被中途唤醒),休眠结束后才会检查任务的取消状态。 - 这个休眠的线程是GCD全局队列中的后台线程,不是主线程。
3. cancel操作的具体影响(针对雷达重连场景)
你的代码存在一个逻辑问题:在提交timeoutWorkItem后立刻调用cancel(),会导致任务还未开始执行就被标记为取消,根本不会进入重连逻辑。正常应该在App进入后台的时机(比如applicationDidEnterBackground)调用cancel,而非在run()函数内直接调用。
如果是正确时机调用cancel(),影响分两种情况:
- 任务未开始执行:GCD会直接跳过该任务,不会执行任何重连逻辑。
- 任务已在执行中:
- 当前的
Thread.sleep休眠不会被打断,线程会等到休眠结束。 - 你的代码没有在循环内检查任务的取消状态,所以即使调用了
cancel(),重连循环仍会跑完所有重试次数,直到doRetry变为false。也就是说,当前代码的cancel()对正在运行的重连逻辑几乎无效。
- 当前的
优化建议
要让cancel()真正生效,需要在循环内加入取消状态判断:
while (doRetry && !self.timeoutWorkItem!.isCancelled) { Thread.sleep(forTimeInterval: TimeInterval(self.mTimeoutMilliSec)) // 休眠后再次检查,避免已取消仍执行重连 if self.timeoutWorkItem!.isCancelled { break } retryNum += 1 if (retryNum <= self.mNumRetries) { SessionController.sharedController.invokeWriteData(responseMsgId: self.mResponseMsgId, bytes: self.mMsgOut) } else { doRetry = false } }
内容的提问来源于stack exchange,提问作者Joice George
相关产品推荐
相关产品推荐

