尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

接上篇ios

接上篇ios iOS端对应关系PythonThreadPoolExecutor(max_workers)→ 管控线程池内部任务只限制本池靠worker线程数量做并发控制threading.Semaphore(DispatchSemaphore)→ 独立计数器对象跨队列全局限流只保护某一段代码iOS这边也完完全全有一模一样的差异两套工具各自定位不同iOS 两套工具①OperationQueue.maxConcurrentOperationCount等价 PythonThreadPoolExecutor(max_workers)letqueueOperationQueue()queue.maxConcurrentOperationCount3//最多同时3个Operation执行foriin0..10{queue.addOperation{//任务逻辑}}管控范围只管控丢进这个OperationQueue里面的任务。别的队列全局GCD队列、另一个OperationQueue完全管不到。原理队列内部管理底层内核线程最多同时跑N个任务多余任务在队列内部排队。特点任务一加入Operation只要开始执行就占用一条底层线程直到整个Operation结束。整个任务生命周期占用线程不能只对其中一小段代码做闸门。GCD本身没有直接设置最大并发的APIGCD全局并发队列不能限制并发数GCD要限制并发只能两种方案用DispatchSemaphore自定义OperationQueue封装GCD任务②DispatchSemaphoreGCD信号量等价 Pythonthreading.SemaphoreletsemDispatchSemaphore(value:3)letglobalQDispatchQueue.global()foriin0..10{globalQ.async{//这里代码不限流可以疯狂并发heavyCalc()sem.wait()//仅仅这一段做闸门networkRequest()sem.signal()}}它是独立计数器对象不管任务来自哪个队列global队列、自定义队列、别的OperationQueue只要调用wait()就会被限流。可以做到只有中间一小段临界代码被限流前后代码不受限制。代价wait()会阻塞当前内核线程会引发线程爆炸。核心差异iOS版和Python一一对应iOS工具管控什么管控范围特点Python对等物OperationQueue.maxConcurrentOperationCount任务整体控制同时执行多少Operation仅本队列内部的任务任务一旦执行全程占住线程不能只限制片段代码ThreadPoolExecutor(max_workers)DispatchSemaphore一段临界区代码所有队列全局生效可以只保护一小段代码但是wait会阻塞内核线程容易线程爆炸threading.SemaphoreiOS场景举例什么时候选哪个场景1所有任务统一提交到同一个队列整个任务都需要并发控制比如批量下载图片每一个operation完整就是一次下载。直接用OperationQueue maxConcurrentOperationCount。简单干净不要套信号量。对应Python全部任务丢进同一个ThreadPoolExecutor设置max_workers。场景2多处不同来源的任务都调用同一个接口需要全局总并发限制A处global队列异步B处另一个OperationQueue两处都会调用同一个网络接口希望全局最多同时3个网络请求。OperationQueue管不到跨队列。这时用全局DispatchSemaphore。对应Python多处不同线程源全局threading.Semaphore。场景3一个任务大部分逻辑不需要限流只有中间一小块网络调用要限流globalQ.async{doSomeHeavyLocalWork()//随便跑不限流sem.wait()apiCall()//仅这里限流sem.signal()}Operation做不到Operation粒度是整个任务。只能用DispatchSemaphore。Python线程池任务内部局部用threading.Semaphore保护一小段。iOS里一个非常经典错误和Python一样OperationQueue设置maxConcurrentOperationCount5外面再套一个DispatchSemaphore(value2)queue.maxConcurrentOperationCount5//添加很多operation//operation内部执行 sem.wait()会发生底层一次性开5条内核线程其中3条线程卡在sem.wait()原地阻塞休眠线程被白白占用浪费内核资源。✅最佳实践如果任务全部交给本队列直接把maxConcurrentOperationCount设置成目标并发数不要再叠加信号量。只有跨队列、局部代码段限流才上DispatchSemaphore。上面全部是GCD / OperationQueue基于内核线程Swift Concurrencyasync/await世界的对应AsyncSemaphore 对应Pythonasyncio.SemaphoreTask是用户态对象await sem.wait()挂起Task归还底层worker线程不会阻塞内核线程没有线程爆炸问题。同样是保护一段临界区可以跨多处Task做全局限流。Swift Concurrency没有类似ThreadPoolExecutor这种手动设置最大worker线程的APIworker线程数量由runtime自动等于CPU核心数你不能手动调。Swift Concurrency中你想控制并发几乎就只用AsyncSemaphore。⚠️ Swift Concurrency千万不要混用DispatchSemaphore会把协作池worker线程阻塞死。把整套逻辑做一个总对照表模型PythoniOS关键点内核线程模型阻塞OS线程ThreadPoolExecutor(max_workers)OperationQueue.maxConcurrentOperationCount只管自己池/队列任务全程占用线程内核线程模型阻塞OS线程threading.SemaphoreDispatchSemaphore独立计数器跨队列可只保护片段会阻塞线程线程爆炸风险协程模型挂起释放OS线程asyncio.SemaphoreAsyncSemaphore挂起Task/协程不阻塞内核线程做并发闸门一句话总结Python线程池 ≈ iOS OperationQueue管自己内部全部任务粒度是整个任务。Python threading.Semaphore ≈ iOS DispatchSemaphore独立计数器可以跨来源、只保护一小段代码但代价是阻塞内核线程。协程那一套asyncio / Swift Concurrency没有“线程池手动设置max workers”靠协程信号量做闸门不会阻塞内核线程。补充一个很多iOS开发者踩坑GCD全局并发队列不能设置最大并发数GCD全局队列会疯狂开线程所以GCD做并发限流只能依靠DispatchSemaphore这也是为什么老项目大量见到DispatchSemaphore。
返回列表