可以从多个线程等待相同的任务 - 等待线程安全吗? [英] Is it ok to await the same task from multiple threads - is await thread safe?

查看:22
本文介绍了可以从多个线程等待相同的任务 - 等待线程安全吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

等待线程安全吗?似乎 Task 类是线程安全的,所以我想等待它也是线程安全的,但我没有在任何地方找到确认.线程安全也是自定义等待程序的要求 - 我的意思是 IsCompleted、GetAwaiter 等方法?IE.如果这些方法不是线程安全的,那么 await 是线程安全的吗?但是,我不希望在短期内需要自定义等待器.

Is await thread safe? It seems the Task class is thread safe so I guess awaiting it is also thread safe but I haven't found a confirmation anywhere. Also is thread safety a requirement for custom awaiter - I mean for the IsCompleted, GetAwaiter, etc. methods? I.e. if those methods are not thread safe, will await be thread safe? However, I don't expect needing a custom awaiter anytime soon.

一个用户场景的例子:假设我有一个后台任务异步返回一个结果,然后在多个线程中使用:

An example of user scenario: Let's say I have a background task which returns a result asynchronously, which is then used from multiple threads:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace scratch1
{
    class Foo
    {
        Task<int> _task;

        public Foo()
        {
            _task = Task.Run(async () => { await Task.Delay(5000); return 5; });
        }

        // Called from multiple threads
        public async Task<int> Bar(int i)
        {
            return (await _task) + i;
        }
    }

    class Program
    {
        public static void Main(string[] args)
        {
            Foo foo = new Foo();

            List<Task> tasks = new List<Task>();
            foreach (var i in Enumerable.Range(0, 100))
            {
                tasks.Add(Task.Run(async () => { Console.WriteLine(await foo.Bar(i)); })); 
            }

            Task.WaitAll(tasks.ToArray());
        }
    }
}

推荐答案

正如您所提到的,await 足够细,以至于它一开始就看不到线程.

As you alluded to, await is thin enough that it doesn't see threads in the first place.

await(状态机中编译器生成的代码,以及BCL 中的支持类)相关的代码一次只能在一个线程上运行.(从awaitable返回时可以切换到不同的线程,但之前的运行已经完成)

The code associated with await (the compiler-generated code within the state machine, and the support classes in the BCL) will only ever run on one thread at a time. (it can switch to a different thread when coming back from the awaitable, but the previous run will have already finished)

实际的线程安全取决于您正在等待的对象.
它必须有一种线程安全的方式来添加回调(或者 await 一次两次可能会中断).

The actual thread-safety depends on the object you're awaiting.
It must have a thread-safe way to add callbacks (or awaiting it twice at once may break).

此外,它必须准确地调用一次回调,否则可能会破坏状态机.(特别是,如果它同时在两个线程上运行它的回调,事情会变得非常糟糕)

In addition, it must call the callback exactly once, or it may break the state machine. (in particular, if it runs its callback on two threads at the same time, things will go horribly wrong)

Task 是线程安全的.

这篇关于可以从多个线程等待相同的任务 - 等待线程安全吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆