我正在尝试Operation
在辅助项目中使用s,而不是在整个网络代码中乱扔基于闭包的回调,以帮助消除嵌套调用。因此,我在阅读有关该主题的文章时,遇到了此实现:
open class AsynchronousOperation: Operation {
// MARK: - Properties
private let stateQueue = DispatchQueue(label: "asynchronous.operation.state", attributes: .concurrent)
private var rawState = OperationState.ready
private dynamic var state: OperationState {
get {
return stateQueue.sync(execute: {
rawState
})
}
set {
willChangeValue(forKey: "state")
stateQueue.sync(flags: .barrier, execute: {
rawState = newValue
})
didChangeValue(forKey: "state")
}
}
public final override var isReady: Bool {
return state == .ready && super.isReady
}
public final override var isExecuting: Bool {
return state == .executing
}
public final override var isFinished: Bool {
return state == .finished
}
public final override var isAsynchronous: Bool {
return true
}
// MARK: - NSObject
private dynamic class func keyPathsForValuesAffectingIsReady() -> Set<String> {
return ["state"]
}
private dynamic class func keyPathsForValuesAffectingIsExecuting() -> Set<String> {
return ["state"]
}
private dynamic class func keyPathsForValuesAffectingIsFinished() -> Set<String> {
return ["state"]
}
// MARK: - Foundation.Operation
public final override func start() {
super.start()
if isCancelled {
finish()
return
}
state = .executing
execute()
}
// MARK: - Public
/// Subclasses must implement this to perform their work and they must not call `super`. The default implementation of this function throws an exception.
open func execute() {
fatalError("Subclasses must implement `execute`.")
}
/// Call this function after any work is done or after a call to `cancel()` to move the operation into a completed state.
public final func finish() {
state = .finished
}
}
@objc private enum OperationState: Int {
case ready
case executing
case finished
}
Operation
我希望对该子类有一些实现细节,以帮助他们理解。
该stateQueue
物业的目的是什么?我看到它是由计算属性使用get
和set
的state
,但是我找不到任何说明它们使用的sync:flags:execute
和sync:execute
方法的文档。
NSObject
返回部分中的三个类方法的目的是什么["state"]
?我看不到它们在任何地方都被使用过。我在中找到了NSObject
,class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String>
但似乎并不能帮助我理解为什么要声明这些方法。
你说:
1.
该stateQueue
物业的目的是什么?我看到state
计算属性的get和set正在使用它,但是找不到任何解释它们使用的sync:flags:execute
和sync:execute
方法的文档。
此代码“同步”对属性的访问以使其线程安全。至于为什么你需要做的是,看到的Operation
文件,其中建议:
多核注意事项
…当您继承子类时
NSOperation
,必须确保从多个线程中调用的所有重写方法都可以安全使用。如果在子类中实现自定义方法(例如自定义数据访问器),则还必须确保这些方法是线程安全的。因此,必须同步访问操作中的任何数据变量,以防止潜在的数据损坏。有关同步的更多信息,请参见《线程编程指南》。
关于此并发队列用于同步的确切使用,这称为“读取器-写入器”模式。读取器-
写入器模式的基本概念是,读取可以相对于彼此并发发生(因此sync
,没有障碍),但是绝对不能相对于该属性的任何其他访问同时进行写入(因此async
有障碍)。
例如,您可以像这样在数组上实现用于线程安全的读写器:
class ThreadSafeArray<T> {
private var values: [T]
private let queue = DispatchQueue(label: "...", attributes: .concurrent)
init(_ values: [T]) {
self.values = values
}
func reader<U>(block: () throws -> U) rethrows -> U {
return try queue.sync {
try block()
}
}
func writer(block: @escaping (inout [T]) -> Void) {
queue.async(flags: .barrier) {
block(&self.values)
}
}
// e.g. you might use `reader` and `writer` like the following:
subscript(_ index: Int) -> T {
get { reader { values[index] } }
set { writer { $0[index] = newValue } }
}
func append(_ value: T) {
writer { $0.append(value) }
}
func remove(at index: Int) {
writer { $0.remove(at: index)}
}
}
显然,在此Operation
子类中使用reader-writer 更加简单,但是上面说明了这种模式。
您还问:
2.
NSObject
返回部分中的三个类方法的目的是什么["state"]
?我看不到它们在任何地方都被使用过。我在中找到了NSObject
,class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String>
但似乎并不能帮助我理解为什么要声明这些方法。
这些是确保变更的只是方法state
的属性的属性触发志愿通知isReady
,isExecuting
以及isFinished
。这三个键的KVO通知对于异步操作的正确运行至关重要。无论如何,《键值观察编程指南:注册从属键》中概述了该语法。
keyPathsForValuesAffectingValue
您找到的方法是相关的。您可以使用该方法注册依赖键,也可以使用原始代码段中所示的各个方法。
顺便说一句,这是AsynchronousOperation
您提供的课程的修订版,即:
super.start()
。如start
文档所述(强调):如果要实现并发操作,则必须重写此方法并使用它来启动操作。 您的自定义实现不得
super
在任何时候调用。
@objc
在Swift 4中html" target="_blank">添加必需项。
重命名execute
为use main
,这是Operation
子类的约定。
声明isReady
为final
属性是不合适的。任何子类都应有权进一步完善其isReady
逻辑(尽管我们承认很少这样做)。
使用#keyPath
,使代码更安全/健壮。
使用dynamic
属性时,您无需手动进行KVO通知。在此示例中,不需要手动调用willChangeValue
和didChangeValue
。
进行更改finish
,使其仅在.finished
尚未完成时才进入状态。
从而:
public class AsynchronousOperation: Operation {
/// State for this operation.
@objc private enum OperationState: Int {
case ready
case executing
case finished
}
/// Concurrent queue for synchronizing access to `state`.
private let stateQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".rw.state", attributes: .concurrent)
/// Private backing stored property for `state`.
private var _state: OperationState = .ready
/// The state of the operation
@objc private dynamic var state: OperationState {
get { return stateQueue.sync { _state } }
set { stateQueue.async(flags: .barrier) { self._state = newValue } }
}
// MARK: - Various `Operation` properties
open override var isReady: Bool { return state == .ready && super.isReady }
public final override var isExecuting: Bool { return state == .executing }
public final override var isFinished: Bool { return state == .finished }
public final override var isAsynchronous: Bool { return true }
// KVN for dependent properties
open override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
if ["isReady", "isFinished", "isExecuting"].contains(key) {
return [#keyPath(state)]
}
return super.keyPathsForValuesAffectingValue(forKey: key)
}
// Start
public final override func start() {
if isCancelled {
state = .finished
return
}
state = .executing
main()
}
/// Subclasses must implement this to perform their work and they must not call `super`. The default implementation of this function throws an exception.
open override func main() {
fatalError("Subclasses must implement `main`.")
}
/// Call this function to finish an operation that is currently executing
public final func finish() {
if !isFinished { state = .finished }
}
}
概述 定时器 Promise 对象
我在单元测试(用C#编写)中存根了必要的方法等,但问题是在断言测试之前异步操作没有完成。 我怎么才能绕过这个?我应该创建一个模拟TaskFactory或任何其他技巧来单元测试异步操作吗?
import { QuoteComponent } from './quote.component'; import { provide } from '@angular/core'; import { async, TestBed, fakeAsync, tick, } from '@angular/core/testing'; class MockQuoteService {
下面的这些操作符属于单独的rxjava-async模块,它们用于将同步对象转换为Observable。 start( ) — 创建一个Observable,它发射一个函数的返回值 toAsync( ) or asyncAction( ) or asyncFunc( ) — 将一个函数或者Action转换为已Observable,它执行这个函数并发射函数的返回值 startFuture( ) — 将
单线程模型 单线程模型指的是,JavaScript 只在一个线程上运行。也就是说,JavaScript 同时只能执行一个任务,其他任务都必须在后面排队等待。 注意,JavaScript 只在一个线程上运行,不代表 JavaScript 引擎只有一个线程。事实上,JavaScript 引擎有多个线程,单个脚本只能在一个线程上运行(称为主线程),其他线程都是在后台配合。 JavaScript 之所以采
如果这被认为是一个可接受的实践,我需要什么-如果有-错误处理?我的理解是,task.wait()将重新抛出异步操作抛出的任何异常,并且我没有提供任何取消异步操作的机制。仅仅调用task.wait()就足够了吗?