fix(concurrency): nonisolated(unsafe) static shared + 修同 actor 内冗余 await
项目开启了 -default-isolation=MainActor upcoming feature,导致:
1. static let shared 默认被视为 MainActor 隔离,即使 class 标了
@unchecked Sendable,从其他 actor(如 AIRuntime)同步访问仍报
"Expression is 'async' but is not marked with 'await'".
修法:ModelStore.shared 和 FileVault.shared 都加 nonisolated(unsafe)
修饰,明确"任何隔离上下文都可同步访问"。
2. AIRuntime.generate() 内的 Task { ... } 继承 AIRuntime actor 隔离,
self.recordRate 是同 actor 内部调用,不需要 await,否则报
"No 'async' operations occur within 'await' expression".
修法:去掉冗余的 await。
** BUILD SUCCEEDED ** 已验证。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -80,7 +80,9 @@ actor AIRuntime {
|
|||||||
// session.generate 跨 actor 边界,需要 await
|
// session.generate 跨 actor 边界,需要 await
|
||||||
let stream = await session.generate(prompt: prompt, maxTokens: maxTokens)
|
let stream = await session.generate(prompt: prompt, maxTokens: maxTokens)
|
||||||
for try await chunk in stream {
|
for try await chunk in stream {
|
||||||
await self.recordRate(chunk.decodeRate)
|
// Task 闭包在 generate() 内启动,继承 AIRuntime 的 actor 隔离;
|
||||||
|
// 调用同 actor 的 recordRate 不需要 await
|
||||||
|
self.recordRate(chunk.decodeRate)
|
||||||
continuation.yield(chunk)
|
continuation.yield(chunk)
|
||||||
}
|
}
|
||||||
continuation.finish()
|
continuation.finish()
|
||||||
|
|||||||
@@ -21,8 +21,10 @@ enum ModelKind: String, CaseIterable {
|
|||||||
|
|
||||||
/// `@unchecked Sendable`:rootURL 是 let,方法只读 filesystem(线程安全),
|
/// `@unchecked Sendable`:rootURL 是 let,方法只读 filesystem(线程安全),
|
||||||
/// 可被任意 actor / Task 跨边界访问。
|
/// 可被任意 actor / Task 跨边界访问。
|
||||||
|
/// `nonisolated(unsafe) shared`:项目开启 `-default-isolation=MainActor` 后
|
||||||
|
/// static 默认 MainActor 隔离,跨 actor 访问需要 await。这里手动 opt-out。
|
||||||
final class ModelStore: @unchecked Sendable {
|
final class ModelStore: @unchecked Sendable {
|
||||||
static let shared: ModelStore = {
|
nonisolated(unsafe) static let shared: ModelStore = {
|
||||||
do {
|
do {
|
||||||
let appSupport = try FileManager.default.url(
|
let appSupport = try FileManager.default.url(
|
||||||
for: .applicationSupportDirectory,
|
for: .applicationSupportDirectory,
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ enum FileVaultError: Error {
|
|||||||
|
|
||||||
/// `@unchecked Sendable`:rootURL 是 let,方法只 I/O 到沙盒目录(线程安全),
|
/// `@unchecked Sendable`:rootURL 是 let,方法只 I/O 到沙盒目录(线程安全),
|
||||||
/// 可被任意 actor / Task 跨边界访问。
|
/// 可被任意 actor / Task 跨边界访问。
|
||||||
|
/// `nonisolated(unsafe) shared`:见 ModelStore 同款注释。
|
||||||
final class FileVault: @unchecked Sendable {
|
final class FileVault: @unchecked Sendable {
|
||||||
static let shared: FileVault = {
|
nonisolated(unsafe) static let shared: FileVault = {
|
||||||
do {
|
do {
|
||||||
let appSupport = try FileManager.default.url(
|
let appSupport = try FileManager.default.url(
|
||||||
for: .applicationSupportDirectory,
|
for: .applicationSupportDirectory,
|
||||||
|
|||||||
Reference in New Issue
Block a user