[英]Get current dispatch queue?
我有一個方法應該支持從任何隊列中調用,並且應該支持。
它自己在后台線程中運行一些代碼,然后在它返回一個值給它的塊參數時使用dispatch_get_main_queue
。
如果它不是在進入方法時,我不希望它強制進入主隊列。 有沒有辦法獲得指向當前調度隊列的指針?
如果您正在使用NSOperationQueue
,它可以為您提供當前的調度隊列。
NSOperationQueue 有類函數[NSOperationQueue currentQueue]
,它將當前隊列作為 NSOperationQueue 對象返回。 要獲取調度隊列對象,您可以使用[NSOperationQueue currentQueue].underlyingQueue
,它將您的當前隊列作為dispatch_queue_t
返回。
斯威夫特 3:
if let currentDispatch = OperationQueue.current?.underlyingQueue {
print(currentDispatch)
}
- 適用於主隊列!
隨着dispatch_get_current_queue()
的棄用,實際上無法知道您正在執行哪個隊列。 如果您仔細閱讀GCD 源代碼,您最終會發現這是因為“我在哪個隊列上執行?”這個問題可能有多種答案。 (因為隊列最終以全局隊列之一為目標,等等)
如果您想保證未來塊在特定隊列上運行,那么唯一的方法是讓您的 API 接受隊列作為參數以及完成塊。 這讓調用者決定在何處執行完成。
如果僅僅知道調用者是否在主線程上就足夠了,您可以使用+[NSThread isMainThread]
來查找。 在一般情況下,在主 GCD 隊列上執行的所有塊都將在主線程上執行。 (此規則的一個例外是,如果您的應用程序使用dispatch_main()
代替主運行循環,您將必須使用dispatch_get_specific
和朋友來確定您正在主隊列上執行——這是一種相對罕見的情況.) 更常見的是,注意並非所有在主線程上執行的代碼都通過 GCD 在主隊列上執行; GCD 從屬於主線程 runloop。 對於您的具體情況,這聽起來可能就足夠了。
您確實可以選擇“ dispatch_get_current_queue()
” ,但是 iOS 6.1 SDK 使用以下免責聲明定義了此 API:
" Recommended for debugging and logging purposes only:
"
和
" This function is deprecated and will be removed in a future release.
"。
這是另一個相關問題,如果您想要面向未來的代碼,您可以考慮一些替代方案。
隨着dispatch_get_current_queue()
的棄用,您無法直接獲得指向正在運行的隊列的指針,但是您可以通過調用dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)
來獲取當前隊列的標簽,這確實給了您一些靈活性。
您始終可以通過比較它們的標簽來檢查您是否在該特定隊列中,因此在您的情況下,如果您不想將其強制在主隊列上,則在進入該方法時,您可以使用以下標志:
let isOnMainQueue = (dispatch_queue_get_label(dispatch_get_main_queue()) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))
如果您在全局隊列上運行,您將獲得與其 QOS 類型相關聯的隊列標簽,該標簽可以是以下之一:
com.apple.root.user-interactive-qos //qos_class_t(rawValue: 33)
com.apple.root.user-initiated-qos //qos_class_t(rawValue: 25)
com.apple.root.default-qos //qos_class_t(rawValue: 21)
com.apple.root.utility-qos //qos_class_t(rawValue: 17)
com.apple.root.background-qos //qos_class_t(rawValue: 9)
然后您可以使用dispatch_get_global_queue(qos_class_self(), 0)
它將返回您正在運行的相同全局隊列。
但是我相信 Apple 特別不鼓勵我們將邏輯綁定到我們被調用的隊列,因此最好將其用於專門的調試目的。
基於奧列格·巴里諾夫的回答
import Foundation
// MARK: private functionality
extension DispatchQueue {
private struct QueueReference { weak var queue: DispatchQueue? }
private static let key: DispatchSpecificKey<QueueReference> = {
let key = DispatchSpecificKey<QueueReference>()
setupSystemQueuesDetection(key: key)
return key
}()
private static func _registerDetection(of queues: [DispatchQueue], key: DispatchSpecificKey<QueueReference>) {
queues.forEach { $0.setSpecific(key: key, value: QueueReference(queue: $0)) }
}
private static func setupSystemQueuesDetection(key: DispatchSpecificKey<QueueReference>) {
let queues: [DispatchQueue] = [
.main,
.global(qos: .background),
.global(qos: .default),
.global(qos: .unspecified),
.global(qos: .userInitiated),
.global(qos: .userInteractive),
.global(qos: .utility)
]
_registerDetection(of: queues, key: key)
}
}
// MARK: public functionality
extension DispatchQueue {
static func registerDetection(of queue: DispatchQueue) {
_registerDetection(of: [queue], key: key)
}
static var currentQueueLabel: String? { current?.label }
static var current: DispatchQueue? { getSpecific(key: key)?.queue }
}
檢測系統隊列
DispatchQueue.currentQueueLabel
DispatchQueue.current
DispatchQueue.global(qos: .default) == DispatchQueue.current
DispatchQueue.main === DispatchQueue.current
檢測自定義隊列
let queue = DispatchQueue(label: "queue-sample")
DispatchQueue.registerDetection(of: queue)
if DispatchQueue.current == queue { ... }
不要忘記在此處粘貼解決方案代碼。
func subTest(queue: DispatchQueue) {
queue.async {
print("--------------------------------------------------------")
print("queue label: \(DispatchQueue.currentQueueLabel ?? "nil")")
print("print DispatchQueue.current: \(String(describing: DispatchQueue.current))")
print("print queue == DispatchQueue.current: \(queue == DispatchQueue.current)")
print("print queue === DispatchQueue.current: \(queue === DispatchQueue.current)")
print("DispatchQueue.main == DispatchQueue.current: \(DispatchQueue.main == DispatchQueue.current)\n")
}
}
func test() {
subTest(queue: DispatchQueue.main)
sleep(1)
subTest(queue: DispatchQueue.global(qos: .default))
sleep(1)
subTest(queue: DispatchQueue.global(qos: .utility))
sleep(1)
let queue = DispatchQueue(label: "queue-sample")
DispatchQueue.registerDetection(of: queue)
subTest(queue: queue)
sleep(1)
}
test()
DispatchQueue.global(qos: .default).async {
test()
}
--------------------------------------------------------
queue label: com.apple.root.default-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.default-qos[0x7fff89eb47c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false
--------------------------------------------------------
queue label: com.apple.root.utility-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.utility-qos[0x7fff89eb46c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false
--------------------------------------------------------
queue label: queue-sample
print DispatchQueue.current: Optional(<OS_dispatch_queue_serial: queue-sample[0x600000275780] = { xref = 7, ref = 3, sref = 2, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x0060002500000b01, enqueued, max qos 5, draining on 0xb03, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false
--------------------------------------------------------
queue label: com.apple.main-thread
print DispatchQueue.current: Optional(<OS_dispatch_queue_main: com.apple.main-thread[0x7fff89eb43c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x001ffe9000000300, dirty, in-flight = 0, thread = 0x303 }>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: true
--------------------------------------------------------
queue label: com.apple.main-thread
print DispatchQueue.current: Optional(<OS_dispatch_queue_main: com.apple.main-thread[0x7fff89eb43c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x001ffe9000000300, dirty, in-flight = 0, thread = 0x303 }>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: true
--------------------------------------------------------
queue label: com.apple.root.default-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.default-qos[0x7fff89eb47c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false
--------------------------------------------------------
queue label: com.apple.root.utility-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.utility-qos[0x7fff89eb46c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false
--------------------------------------------------------
queue label: queue-sample
print DispatchQueue.current: Optional(<OS_dispatch_queue_serial: queue-sample[0x60000027a280] = { xref = 7, ref = 3, sref = 2, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x0060002500000b01, enqueued, max qos 5, draining on 0xb03, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false
基於SQLite.swift的來源。
如果您想檢查您是否在自己的特殊調度隊列中:
class Worker {
private static let queueKey = DispatchSpecificKey<Int>()
private lazy var queueContext = unsafeBitCast(self, to: Int.self)
private lazy var queue: DispatchQueue = {
let value = DispatchQueue(label: "com.example.App.Worker")
value.setSpecific(key: Worker.queueKey, value: queueContext)
return value
}()
func test(x: Int) -> Int {
return dispatchSync {
return x > 2 ? test(x: x - 1) * x : x
}
}
private func dispatchSync<T>(_ block: () throws -> T) rethrows -> T {
if DispatchQueue.getSpecific(key: Worker.queueKey) != queueContext {
return try queue.sync(execute: block)
}
return try block()
}
}
let worker = Worker()
worker.test(x: 5)
作為此NSOBject
方法的替代方法performSelector:withObject:afterDelay:在當前線程的運行循環上調度調用。 根據文檔:
該方法設置了一個計時器來在當前線程的運行循環上執行 aSelector 消息。
顯然,我建議在延遲為零的情況下使用它,根據文檔再次:
指定延遲 0 不一定會導致選擇器立即執行。 選擇器仍然在線程的運行循環中排隊並盡快執行。
不幸的是,它只需要一個參數,因此如果您的方法需要更多或更少的時間,則可能需要一些解決方法。
我注意到的另一件事是這種方法不適用於協議,而只能用於實現。 這是因為這個方法存在於NSObject
類別中,而不是在NSObject
接口中(請參閱下面的 PS)。 這可以通過強制轉換為id
輕松解決。
PS:存在兩個不同的NSObject
,一個協議和一個實現。 注意NSObject
聲明:
@interface NSObject <NSObject> { ... }
這可能看起來很奇怪,但一個是被聲明的(在@interface
之后),另一個是先前聲明的協議(在<
和>
之間)。 當聲明一個擴展 NSObject 的協議(即@protocol Foo <NSObject>
)時,協議繼承了后者的方法,而不是前者。 最終協議是由一些繼承自NSObject
實現的類實現的,所以所有繼承自NSObject
實現的實例仍然有效。 但我跑題了。
其實還是有辦法比較隊列的。
設置隊列時,請確保添加標簽。 出於我的目的,我有一個共享隊列,用於訪問數據庫以防止數據庫鎖定。 在我的 DB.m 文件中,我定義了共享隊列函數,如:
const char *kTransactionQueueLabel = "DB_TRANSACTION_DISPATCH_QUEUE";
+ (dispatch_queue_t)sharedDBTransactionQueue {
static dispatch_queue_t sharedDBQueue = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedDBQueue = dispatch_queue_create(kTransactionQueueLabel, DISPATCH_QUEUE_SERIAL);
});
return sharedDBQueue;
}
共享 db 事務隊列在文件中本地使用,以將所有執行分派到數據庫。 但是,還有一個公共訪問器,允許將整個事務分派到數據庫。 所以在內部,如果從事務隊列內部調用數據庫訪問方法,我們需要在不同的隊列內部調度(所有同步調度)。 所以在內部,我總是使用下面的 getter 在適當的隊列上調度。
/**
* @description Decide which queue to use - if we are already in a transaction, use the internal access queue, otherwise use the shared transaction queue.
*/
- (dispatch_queue_t)getProperQueueForExecution {
const char *currentLabel = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
dispatch_queue_t sharedAccessQueue = [DB sharedDBTransactionQueue];
if (strcmp(currentLabel, kTransactionQueueLabel) == 0) {
sharedAccessQueue = [DB sharedInternalDBAccessQueue];
}
return sharedAccessQueue;
}
希望這會有所幫助。 對不起,這個例子太長了。 它的要點是你可以使用
const char *currentLabel = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
獲取當前隊列的標簽並與定義的標簽進行比較。
如果您只對當前的 QOS 感興趣,請檢查Thread.current.qualityOfService
的值。
我有原始帖子提到的相同功能要求。 您應該能夠在任何隊列上調用此異步函數,但如果在主隊列上調用,則回調到主隊列上的用戶。 我只是像這樣處理它:
// cache value for if we should callback on main queue
BOOL callbackOnMT = [NSThread isMainThread];
// ...
// ... do async work...
// ...
if (callbackOnMT && ![NSThread isMainThread]){
dispatch_async(dispatch_get_main_queue(), ^{
// callback to user on main queue
// as they called this function on main queue
callbackToUser();
});
}
else{
// callback to user on our current queue
// as they called this function on a non-main queue
callbackToUser();
}
獲取當前隊列的標簽並使用定義的標簽進行比較。
let queueName = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.