同步和异步如何与线程安全一起工作?
How both sync and async work with thread safe?
在 Swift 中,我们可以利用 DispatchQueue
来防止竞争条件。通过使用串行队列,所有事情都按顺序执行,从https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
Serial queues (also known as private dispatch queues) execute one task
at a time in the order in which they are added to the queue. The
currently executing task runs on a distinct thread (which can vary
from task to task) that is managed by the dispatch queue. Serial
queues are often used to synchronize access to a specific resource.
但我们可以通过在 async
中执行 sync
轻松创建死锁 How do I create a deadlock in Grand Central Dispatch?
let serialQueue = DispatchQueue(label: "Cache.Storage.SerialQueue")
serialQueue.async {
serialQueue.sync {
print("perform some job")
}
print("this can't be reached")
}
防止死锁的唯一方法是使用 2 个串行队列,每个队列用于 sync
和 async
函数版本。但是当 writeSync
和 writeAsync
同时发生时,这可能会导致罕见的情况。
我在 fs module 中看到它同时支持 sync
和 async
函数,例如 fs.writeFileSync(file, data[, options])
和 fs.writeFile(file, data[, options], callback)
。通过允许这两个版本,是否意味着用户可以按照他们想要的任何顺序使用它们?所以他们很容易像我们上面那样制造死锁?
所以也许 fs
有一个聪明的方法可以应用到 Swift?我们如何以线程安全的方式同时支持 sync
和 async
?
serialQueue.async {
serialQueue.sync {
print("perform some job")
}
}
之所以会死锁,是因为这段代码将第二个任务排入同一个调度队列,然后等待第二个任务完成。然而,第二个任务甚至无法启动,因为它是一个串行队列,而第一个任务仍在执行(尽管被内部信号量阻塞)。
避免这种死锁的方法是永远不要那样做。当您认为可以通过以下方式实现相同的效果时,这尤其愚蠢:
serialQueue.async {
print("perform some job")
}
有一些 运行 同步任务用例在与您所在队列不同的队列中,例如
- 如果另一个队列是主队列,并且您想在 UI 中做一些事情,然后再继续
- 作为不同队列中任务之间同步的一种方式,例如,如果你想确保另一个队列中的所有当前任务在继续之前都已完成。
然而,没有理由在同一个队列上同步做某事,你还不如做某事。或者换句话说,如果你只是一个接一个地写语句,它们已经在同一个队列上同步执行了。
I see in fs module that it supports both sync and async functions, like fs.writeFileSync(file, data[, options]) and fs.writeFile(file, data[, options], callback). By allowing both 2 versions, it means users can use them in any order they want? So they can easily create deadlock like what we did above?
这取决于两个 API 的实现方式。调用的同步版本可能只是执行调用而不会影响其他线程。如果它确实抓住了另一个线程,然后等待直到另一个线程完成,那么是的,如果 node.js
服务器用完线程,则可能会出现死锁。
在 Swift 中,我们可以利用 DispatchQueue
来防止竞争条件。通过使用串行队列,所有事情都按顺序执行,从https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
Serial queues (also known as private dispatch queues) execute one task at a time in the order in which they are added to the queue. The currently executing task runs on a distinct thread (which can vary from task to task) that is managed by the dispatch queue. Serial queues are often used to synchronize access to a specific resource.
但我们可以通过在 async
sync
轻松创建死锁 How do I create a deadlock in Grand Central Dispatch?
let serialQueue = DispatchQueue(label: "Cache.Storage.SerialQueue")
serialQueue.async {
serialQueue.sync {
print("perform some job")
}
print("this can't be reached")
}
防止死锁的唯一方法是使用 2 个串行队列,每个队列用于 sync
和 async
函数版本。但是当 writeSync
和 writeAsync
同时发生时,这可能会导致罕见的情况。
我在 fs module 中看到它同时支持 sync
和 async
函数,例如 fs.writeFileSync(file, data[, options])
和 fs.writeFile(file, data[, options], callback)
。通过允许这两个版本,是否意味着用户可以按照他们想要的任何顺序使用它们?所以他们很容易像我们上面那样制造死锁?
所以也许 fs
有一个聪明的方法可以应用到 Swift?我们如何以线程安全的方式同时支持 sync
和 async
?
serialQueue.async {
serialQueue.sync {
print("perform some job")
}
}
之所以会死锁,是因为这段代码将第二个任务排入同一个调度队列,然后等待第二个任务完成。然而,第二个任务甚至无法启动,因为它是一个串行队列,而第一个任务仍在执行(尽管被内部信号量阻塞)。
避免这种死锁的方法是永远不要那样做。当您认为可以通过以下方式实现相同的效果时,这尤其愚蠢:
serialQueue.async {
print("perform some job")
}
有一些 运行 同步任务用例在与您所在队列不同的队列中,例如
- 如果另一个队列是主队列,并且您想在 UI 中做一些事情,然后再继续
- 作为不同队列中任务之间同步的一种方式,例如,如果你想确保另一个队列中的所有当前任务在继续之前都已完成。
然而,没有理由在同一个队列上同步做某事,你还不如做某事。或者换句话说,如果你只是一个接一个地写语句,它们已经在同一个队列上同步执行了。
I see in fs module that it supports both sync and async functions, like fs.writeFileSync(file, data[, options]) and fs.writeFile(file, data[, options], callback). By allowing both 2 versions, it means users can use them in any order they want? So they can easily create deadlock like what we did above?
这取决于两个 API 的实现方式。调用的同步版本可能只是执行调用而不会影响其他线程。如果它确实抓住了另一个线程,然后等待直到另一个线程完成,那么是的,如果 node.js
服务器用完线程,则可能会出现死锁。