AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79335356
Accepted
Deepak Sharma
Deepak Sharma
Asked: 2025-01-07 16:41:21 +0800 CST2025-01-07 16:41:21 +0800 CST 2025-01-07 16:41:21 +0800 CST

Swift 中 Sendable 协议有什么用

  • 772

将类或函数标记为Sendable可确保它可以安全地跨越并发边界,值类型是安全的,因为它们实现了写时复制等,我们都可以在 Swift 语言文档中找到。但我的观点是,这Sendable并不保证变量没有数据竞争。即使在基本值类型中,我们也可能存在数据竞争,如Int下面的代码所示。因此,Sendable并不等同于数据可以安全地避免并发访问/修改,它只意味着值可以安全地跨不同线程复制。但我的问题是它解决了什么问题,或者作为构造的重要性是什么Sendable?有人可以解释一下吗?

var num = 0

DispatchQueue.global(qos: .background).async {
    for _ in 0..<100 {
        num += 1 
    }
}

DispatchQueue.global(qos: .background).async {
    for _ in 0..<100 {
        num -= 1 
    }
}
  • 2 2 个回答
  • 59 Views

2 个回答

  • Voted
  1. Best Answer
    2025-01-07T17:27:10+08:002025-01-07T17:27:10+08:00

    正如您所说,Sendable允许编译器推断某个值是否可以安全地跨并发域发送。这非常有用,因为您经常编写跨并发域发送内容的代码。编译器可以检查您的代码是否安全。如果没有Sendable,编译器要么需要禁止任何发送(过于严格),要么允许所有发送(不安全)。

    来自SE-0302:

    程序中的每个 Actor 实例和结构化并发任务都代表一个“单线程孤岛”,这使它们成为包含可变状态包的自然同步点。它们与其他任务并行执行计算,但我们希望此类系统中的绝大多数代码都无需同步 — 建立在 Actor 的逻辑独立性之上,并使用其邮箱作为其数据的同步点。

    因此,一个关键问题是:“我们何时以及如何允许数据在并发域之间传输?”例如,这种传输发生在参与者方法调用的参数和结果以及由结构化并发创建的任务中。

    一个非常简单的例子可以证明Sendable它有多么有用:

    func f(_ x: SomeType) {
        Task {
            print(x)
        }
    }
    

    这安全吗?这取决于 的值是否SomeType可以安全地发送到顶层Task。如果发送不安全,您最终可能会SomeType在 和 它最初来自的地方之间共享的值Task。例如,如果SomeType是一个具有可变属性的类,则可能会导致竞争:

    func g() {
        let x = SomeType()
        f(x) // the task that f creates might run concurrently with the next line!
        x.someProperty = "some new value"
    }
    

    如果SomeType是Sendable,那么编译器就可以允许第一个代码片段进行编译。


    以下是来自 SE-0302 的另一个示例:

    actor SomeActor {
      // async functions are usable *within* the actor, so this
      // is ok to declare.
      func doThing(string: NSMutableString) async {}
    }
    
    // ... but they cannot be called by other code not protected
    // by the actor's mailbox:
    func f(a: SomeActor, myString: NSMutableString) async {
      // error: 'NSMutableString' may not be passed across actors;
      //        it does not conform to 'Sendable'
      await a.doThing(string: myString)
    }
    

    doThing对 Actor 来说是孤立的,Actor 可以将string传递到的存储doThing在其某个属性中。然后,最终NSMutableStringActor 和最初拥有它的任何人共享一个。

    如果我们使用String而不是NSMutableString,那么此代码是安全的,因为String是Sendable。String是写时复制的,因此修改它的参与者不会影响最初拥有它的人。

    • 2
  2. Midhun
    2025-01-07T17:32:16+08:002025-01-07T17:32:16+08:00

    可发送的目的

    • 并发安全:确保类型的值可以在任务或线程之间安全地共享或传递。
    • 编译时检查:编译器强制所有可发送类型的存储属性本身都是可发送的。
    • 防止数据竞争:防止跨并发任务对共享可变状态的不安全访问。

    何时使用 Sendable

    • 使用 Sendable 来发送您想要传递给其他任务或跨线程共享的自定义类型。
    • 标准库类型如 Int、String 和 Array(如果它们的元素是可发送的)已经符合 Sendable。

    示例:符合 Sendable 的自定义类型

    import Foundation
    
    struct SafeData: Sendable {
        let value: Int // Immutable properties are inherently safe
    }
    
    // Example usage
    func performTask(with data: SafeData) async {
        await Task {
            print("Processing data: \(data.value)")
        }.value
    }
    

    示例:将 Sendable 与类一起使用

    对于符合 Sendable 的类,其所有存储属性都必须是不可变的,或者本身符合 Sendable。此外,该类必须标记为 final。

    final class SafeClass: Sendable {
        let value: Int // Immutable property ensures thread safety
    
        init(value: Int) {
            self.value = value
        }
    }
    

    如果属性是可变的,则编译器将发出错误,除非您采取明确措施,例如同步访问或确保排他性。

    • 1

相关问题

  • 将复制活动的序列号添加到 Blob

  • Packer 动态源重复工件

  • 选择每组连续 1 的行

  • 图形 API 调用列表 subscribedSkus 状态权限不足,但已授予权限

  • 根据列值创建单独的 DF 的函数

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve