没有使用Task<T>(异步/等待模式)的任务返回值。

6

我想要写下以下内容:

public string GetSomeValue()
{
    //directly return the value of the Method 'DoSomeHeavyWork'...
    var t = DoSomeHeavyWork();
    return t.Result;
}

public Task<string> DoSomeHeavyWork()
{
    return Task.Run(() => {
        // do some long working progress and return a string
        return "Hello World!";
    });
}

正如您所看到的,为了从DoSomeHeavyWork()返回结果,我使用了Task.Result属性,这样做是可以的,但研究表明这会阻塞线程。

我想使用async/await模式来解决这个问题,但似乎找不到如何实现。

如果按照我的当前知识使用async/await,我最终会得到以下结果:

public async Task<string> GetSomeValue()
{
    //directly return the value of the Method 'DoSomeHeavyWork'...
    var t = DoSomeHeavyWork();
    return await t;
}

public Task<string> DoSomeHeavyWork()
{
    return Task.Run(() => {
        // do some long working progress and return a string
        return "Hello World!";
    });
}

这个解决方案并不完全符合我的需求,因为我只想返回字符串而不是一个Task<string>,如何使用async/await实现这一点呢?


为什么不能返回 Task<string> 呢?因为当你使用 await 等待它时,它会返回一个 string。这不是你想要的吗? - Enigmativity
1个回答

11
你不能这样做。
异步编程的整个重点在于以异步方式运行代码。因此,该代码返回一个未来字符串值的承诺,在.NET中表示为Task<string>。
这样想:如果你的代码调用public string GetSomeValue(),那么在方法返回时,你已经拥有了一个字符串。这是同步的定义。
在你的示例中,你有“繁重”的工作,我理解为“CPU绑定”。在这种情况下,只需同步地执行工作即可。
public string DoSomeHeavyWork()
{
  // do some long working progress and return a string
  return "Hello World!";
}

一般来说,API不应该“撒谎”;如果它们是同步的,则应该具有同步(非Task返回)签名。 编辑:根据您的评论,“繁重”的工作是WCF调用,它是I/O限制的,而不是CPU-bound。
在这种情况下,工作自然是异步的。使用异步WCF方法(而不是Task.Run),并允许异步增加到您的代码库中:
public async Task<string> GetSomeValueAsync()
{
  //directly return the value of the Method 'DoSomeHeavyWork'...
  var t = DoSomeHeavyWorkAsync();
  return await t;
}

public async Task<string> DoSomeHeavyWorkAsync()
{
  // Call asynchronous WCF client.
  await ...;
  return "Hello World!";
}

你会用 Task.Result 属性来解决我的问题吗?或者你知道更好的方法吗?(如果你知道更好的替代方案,提供代码片段将使我非常高兴) - Rand Random
在我的实际示例中,我正在调用一个WCF请求到客户端,并希望有一个异步运行的方法,以便在服务器调用该方法时不会阻塞客户端(服务器/客户端都是WPF)。那么,我应该返回Task对象而不是已解析的字符串/对象吗? - Rand Random
我已经编辑了我的答案,并提供了我首选的解决方案:直接进行工作。而且,我再次进行了编辑,因为“繁重”的工作是一个WCF请求。 - Stephen Cleary
如果WCF客户端实现以下接口: [OperationContract()] Task<string> GetAccountValue(string accNr, string propertyName); 而不是简单的字符串/对象,这并不是问题。 - Rand Random
没错,任何返回Task的操作都是异步的,如果你通过await异步地消费它,那么一切都能正常工作。 - Stephen Cleary
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接