取消未传播



取消不会通过这里的服务类传播

let task = Task<Service.Resource, Error> {
if Task.isCancelled {
throw URLError(.cancelled)
}
return try await service.loadResource()
}

需要对这个函数做什么修改来传播取消?

func loadResource() async throws -> Resource {
let data = try await load()
return try decoder.decode(Resource.self, from: data)
}

在结构化并发中,如果取消一个Task,它的子进程也将被取消。如果您没有看到取消的孩子,下面的一个可能是罪魁祸首:

  • 可能load方法引入了额外的非结构化并发性(即在load方法中引入了另一个Task对象);
  • 可能load方法没有使用可取消的async方法;
  • 也许尝试调用task变量的cancel是错误的…我们需要查看这个task变量的生命周期,以及在Task对象上调用cancel方法的位置。

但是,底线是,如果(a)您在Task中保持结构化并发性,您将享受取消传播;(b)你await一个支持取消的方法


作为题外话,考虑以下内容:

let task = Task<Service.Resource, Error> {
if Task.isCancelled {
throw URLError(.cancelled)
}
return try await service.loadResource()
}

可以简化为:

let task = Task<Service.Resource, Error> {
try Task.checkCancellation()
return try await service.loadResource()
}

不幸的是,这将是有限的效用。如果任务在启动后被取消(很可能是由于参与者重入),那么您可能已经通过了这个测试,等待loadResource(它很可能正在等待load)。更重要的是loadResource(以及它调用的load方法)必须都支持取消。

人们通常会鼓励别人检查if Task.isCancelled {…}或呼叫try Task.checkCancellation()。但更重要的是,确保load支持取消。例如,如果你正在调用URLSessionasync方法,例如data(for:delegate:)data(from:delegate:),它们已经支持取消。

但是如果你在使用Swift并发之前的其他API(可能是在withCheckedContinuationwithUnsafeContinuation中包装的东西),那么你通常会将其包装在withTaskCancellationHandler中,利用底层API提供的任何取消支持。

但是,如果没有看到load方法的实现(以及如何取消这个顶级task),很难进一步提出建议。

相关内容

  • 没有找到相关文章

最新更新