惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Schneier on Security
GbyAI
GbyAI
H
Help Net Security
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
The Blog of Author Tim Ferriss
Vercel News
Vercel News
Microsoft Azure Blog
Microsoft Azure Blog
Google DeepMind News
Google DeepMind News
Stack Overflow Blog
Stack Overflow Blog
AWS News Blog
AWS News Blog
Spread Privacy
Spread Privacy
Apple Machine Learning Research
Apple Machine Learning Research
L
LINUX DO - 最新话题
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
P
Privacy International News Feed
C
CERT Recently Published Vulnerability Notes
C
Cybersecurity and Infrastructure Security Agency CISA
I
Intezer
Hugging Face - Blog
Hugging Face - Blog
H
Heimdal Security Blog
N
News and Events Feed by Topic
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Troy Hunt's Blog
大猫的无限游戏
大猫的无限游戏
SecWiki News
SecWiki News
Martin Fowler
Martin Fowler
人人都是产品经理
人人都是产品经理
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Application and Cybersecurity Blog
Application and Cybersecurity Blog
F
Fortinet All Blogs
Hacker News: Ask HN
Hacker News: Ask HN
Know Your Adversary
Know Your Adversary
Hacker News - Newest:
Hacker News - Newest: "LLM"
博客园 - 聂微东
S
Secure Thoughts
云风的 BLOG
云风的 BLOG
O
OpenAI News
The Cloudflare Blog
Jina AI
Jina AI
U
Unit 42
L
Lohrmann on Cybersecurity
Attack and Defense Labs
Attack and Defense Labs
The Register - Security
The Register - Security
G
Google Developers Blog
量子位
Simon Willison's Weblog
Simon Willison's Weblog
V
Visual Studio Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
G
GRAHAM CLULEY
TaoSecurity Blog
TaoSecurity Blog

博客园 - 世纪末の魔术师

《The Wealth Ladder》读书笔记 项目管理,真正的密码只有一句话 Linq延迟执行陷阱 坚毅,是一种缓慢修理自己的方式 语言的边界,与软件的命运 人类与AI协同进化 《坚毅》第一部分读书笔记 用 System.CommandLine 构建工程级 CLI 工具 用 Command 模式构建可扩展的命令行工具 从哎呦”到语言宇宙 ——读《What Is ChatGPT Doing … And Why Does It Work?》 ⏱️ 深入理解定时器中的【时间轮算法】 🚫 为什么「定时器」不应该是线程安全的? C# AOT编译后——调用其类库方法因顺序出错? 光线追踪和球体追踪 八、方法(method) 二十、异常与状态管理(Exception&State Management) 二十八、IO绑定的异步操作(IO-Bound Async) 二十二、CLR寄宿与AppDomain(CLR Hosting and App Domains ) 二十九、原始线程同步构造(Primitive Thread Synchronization Constructs ) 二十六、线程与并发(Thread Basic) 二十七、计算密集型异步操作(Compute-Bound Asynchronous Operations) 二十三、程序集加载与反射(Assembly Loading and Reflection)
UnitTask中的Forget()与 CTS
世纪末の魔术师 · 2025-10-11 · via 博客园 - 世纪末の魔术师

🎯 结论先行:不是“每个异步方法”都要加 CTS

而是「凡是可能长时间存在、或受生命周期控制的任务」才应该加 CTS。


🧩 一、Forget()CTS 的核心区别

对比项 .Forget() CancellationTokenSource
目的 忽略等待结果 控制任务生命周期
适用场景 轻量、短期任务 长时、可取消任务
是否能终止任务 ❌ 否 ✅ 可以取消
是否捕获异常 ❌ 默认丢弃(除非 .Forget(ResultHandling...)) ✅ 可被 try-catch 捕获
GC 开销 少量(每次创建)

🧭 二、两者协同工作的黄金范式

最佳做法是:

👉「任务逻辑用 CTS 控制生命周期」,
👉「调用者决定是否 await.Forget()」。

示例:

private CancellationTokenSource cts;

private void Start()
{
    cts = new();
    LoadSceneAsync(cts.Token).Forget(); // 调用方选择忽略
}

private async UniTask LoadSceneAsync(CancellationToken token)
{
    await UniTask.Delay(5000, cancellationToken: token);
    Debug.Log("场景加载完成");
}

private void OnDestroy()
{
    cts.Cancel(); // 防止场景切换或对象销毁时任务泄漏
}

💡 解释:

  • LoadSceneAsync 不关心是否被 await;

  • cts.Token 决定任务是否继续;

  • Forget() 让调用方不阻塞,但内部仍受控。


⚙️ 三、什么时候“必须”加 CTS?

场景 是否建议加 CTS 原因
⏳ 延迟逻辑(如 Delay, WaitUntil) ✅ 是 避免对象销毁后继续等待
🔄 循环任务(如 AI 行为、监控) ✅ 是 必须能中断
🌐 异步加载(网络/资源) ✅ 是 用户可能切场景、关闭窗口
⚡ 短期逻辑(如 UI 动画) ❌ 可省略 生命周期很短
🧩 同步逻辑(例如计算) ❌ 不必要 一次执行完即结束
🧠 Editor 模式(非运行时) ✅ 推荐 编辑器中生命周期不稳定

🧱 四、实际对比:有无 CTS 的差异

❌ 无 CTS(任务泄漏)

private async void Start()
{
    await UniTask.Delay(5000);
    Debug.Log("对象早就销毁了,但我还在执行!");
}

✅ 有 CTS(安全终止)

private async void Start()
{
    var token = this.GetCancellationTokenOnDestroy();
    await UniTask.Delay(5000, cancellationToken: token);
    Debug.Log("对象没销毁才会执行到这里");
}

💡 说明:

GetCancellationTokenOnDestroy() 是 UniTask 为 MonoBehaviour 提供的神器,它会在对象销毁时自动取消。


🧩 五、关于 Forget() 的使用建议

✅ 推荐写法:

SomeAsync().Forget(); // 我知道它会跑完,不需要返回结果

⚠️ 不推荐写法:

await SomeAsync().Forget(); // 无意义,Forget返回void

🚨 异常丢失问题:

.Forget() 默认吞异常,你可以这样防御:

SomeAsync().Forget(e => Debug.LogException(e));

🧠 六、实战建议(通俗记忆法)

任务类型 是否加 CTS 是否 Forget
UI 动画
网络请求 ❌(要 await 结果)
AI 行为循环
Editor 扩展操作
一次性逻辑
场景加载 ❌(等待完成)

🔍 七、进阶:组合式 CTS 管理

你可以用一个父级 Token 控制多个异步任务:

var cts = new CancellationTokenSource();

DoA(cts.Token).Forget();
DoB(cts.Token).Forget();
DoC(cts.Token).Forget();

// 一键取消所有
cts.Cancel();

或者组合多个 Token:

var linked = CancellationTokenSource.CreateLinkedTokenSource(token1, token2);
await UniTask.Delay(1000, cancellationToken: linked.Token);

📈 八、性能注意

  • 创建一个 CTS 的开销 ≈ 40~60B GC Alloc;

  • 所以:
    👉 建议在 MonoBehaviour 级别缓存
    👉 而不是每次 async 方法都 new 一个。

private CancellationTokenSource cts;
private void Awake() => cts = new();
private void OnDestroy() => cts.Cancel();

🧩 九、最佳实践模板(生产级推荐)

public class Example : MonoBehaviour
{
    private CancellationTokenSource _cts;

    private void Awake()
    {
        _cts = new();
    }

    private void OnDestroy()
    {
        _cts.Cancel();
        _cts.Dispose();
    }

    private void Start()
    {
        RunAsync(_cts.Token).Forget();
    }

    private async UniTask RunAsync(CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            await UniTask.Delay(1000, cancellationToken: token);
            Debug.Log("持续工作中...");
        }
    }
}

🧠 记忆口诀

Forget 是“不管结局”,CTS 是“能中断结局”。

  • 只要任务可能「超时、循环、依赖对象存在」,就加 CTS

  • 调用方只关心“我是否等待结果”,就用 Forget