任务<task>在C#中是非法的?

时间:2017-03-27 14:15:35

标签: c# multithreading task

此代码在VS2015中提供编译错误

  

错误CS0266无法隐式转换类型&#39; System.Threading.Tasks.Task&#39;到&#39; System.Threading.Tasks.Task&#39;。存在显式转换(您是否错过了演员?)

更新1:在任务而不是任务之后的扩展代码&lt;任务&gt;有人建议。

        int i = 0;
        Task<int> test = Task.Run( () => {
            return i;
        } );
        i = test.Result;
        Task t = Task.Run( () => { } );
        Task<Task> test2 = Task.Run( () => {
            return t;
        } );
        t = test2.Result;

我做错了什么?

UPDATE2: 此代码发出警告(我不想要警告,也没有抑制编译指示)

  

警告CS1998此异步方法缺少等待&#39;运营商并将同步运行。考虑使用&#39; await&#39;运营商等待非阻塞API调用,或等待Task.Run(...)&#39;在后台线程上进行CPU绑定的工作。

        int i = 0;
        Task<int> test = Task.Run( () => {
            return i;
        } );
        i = test.Result;
        Task t = Task.Run( () => { } );
        Task<Task> test2 = Task.Run( async () => {
            return t;
        } );
        t = test2.Result;

更新3: 致所有坚持任务测试的人。

  1. StartAndReturnSecondTaskAsync必须返回第二个任务(执行longOperation2)
  2. StartAndReturnSecondTaskAsync必须是异步的,即UI不能在longOperation1的持续时间内阻止

    public static async Task<Task> StartAndReturnSecondTaskAsync() {
        Task t = await Task.Run( () => {
            return StartAndReturnSecondTask();
        } );
        return t;
    }
    
    public static Task StartAndReturnSecondTask() {
        var importantData = longOperation1();
        return Task.Run( () => {
            longOperation2( importantData );
        } );
    }
    
    ...
    
    Task second = await StartAndReturnSecondTaskAsync();
    

3 个答案:

答案 0 :(得分:1)

Task<Task> 非常常见并且经常出现问题(如果我们错误地等待/等待错误的外部任务):< / p>

  int i = 0;

  Task<int> test = Task.Run(() => {
    return i;
  });

  Task t = Task.Run(() => {
  });

  // please, notice "async"
  Task<Task> test2 = Task.Run(async () => { // <- async: let insist on Task<Task>...
    return t;
  });

Task<Task>

甚至还有扩展方法
  Task backToTask = test2.Unwrap();

在你的情况下你想要

  Task test2 = Task.Run(() => {
    return t;
  });

由于Task.Run为您调用Unwrap()

答案 1 :(得分:1)

这是非常常见但是使用Task.Run来执行某些异步操作,如果使用旧方法StartNew,它会执行您期望的操作,即调度线程池线程启动异步操作,并告诉您异步操作何时完成正在启动

然而,这基本上不是人们真正想要的。他们想知道Task.RUn 中调用的异步操作何时完成。因此,Task.Run将解包任何Task<Task> that would be returned, so that what you're really seeing is the inner任务。

如果真的只想让线程池线程启动任务,并且只知道它何时完成启动,然后你可以使用Task.Factory.StartNew而不代表你展开Task<Task>

答案 2 :(得分:0)

一个简单的解决方案,但没有详细介绍:

可行的代码是:

int i = 0;
Task<int> test = Task.Run(() =>
{
    return i;
});
Task t = Task.Run(() => { });
Task test2 = Task.Run(() =>
{
    return t;
});

如果您采用其他可能使用await的方法,您需要制作上下文async,例如:

public async Task DoesTheThreadedOperations()
{
// Your code in question and other code
}

根据您的更新3

public static async Task StartAndReturnSecondTaskAsync()
{
    await Task.Run(() =>
    {
        return StartAndReturnSecondTask();
    });
}

public static Task StartAndReturnSecondTask()
{
    System.Threading.Thread.Sleep(5000);
    return Task.Run(() =>
    {
        System.Threading.Thread.Sleep(10000);
    });
}

我曾用睡眠来模仿你的长期行动。我希望你不一定要使用Task<Task>。这应该给你足够的力量来攻击你的场景。您可以进一步改进它以通过将这两个操作分成两个不同的线程并将结果从一个传递到另一个来获得您的确切结果,等待您想要的并运行并让其他更长的任务在没有等待的情况下运行。也就是说,从主方法中调用两个方法,等待一个方法,而不是其他方法。