使方法异步
本文关键字:异步 方法 | 更新日期: 2023-09-27 18:08:02
我有一个调用Bing Api的方法。
IEnumerable<WebResult> Search(string query)
我想让它异步,这样如果我对它进行多次调用,每个调用都是独立的。因此,按照这里的建议,我将签名更改为
async Task<IEnumerable<WebResult>> SearchAsynch(string query)
但是我得到了警告
This async method lacks 'await' operators and will run synchronously...
我希望整个方法是异步的(至少这是我认为它应该如何工作)。我怎么做呢?这是我的代码
public async Task<IEnumerable<WebResult>> SearchAsynch(string query)
{
if (query == null)
{
throw new ArgumentNullException("query cannot be null");
}
DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null);
IEnumerable<WebResult> webResults = webQuery.Execute();
return webResults;
}
问题是我不确定在这段代码中等待什么
async
关键字不创建一个新的异步操作,它只是一种更容易地为已经存在的任务(即异步操作)配置延续的方法。
在本例中,DataServiceQuery
类已经提供了异步执行查询的方法。不幸的是,它使用的是旧的异步模型,而不是新的基于Task
的模型,所以你需要使用Task.Factory.FromAsync
来翻译它:
public Task<IEnumerable<WebResult>> SearchAsynch(string query)
{
DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null);
return Task.Factory.FromAsync(webQuery.BeginExecute(null, null)
, asyncResult => webQuery.EndExecute(asyncResult)));
}
在这种特殊情况下,由于您不需要做任何事情,除了创建任务,您根本不需要async
或await
,您可以只返回已构建的任务。如果你想在你得到结果后做一些事情,你可以代替await
任务:
public async Task<IEnumerable<WebResult>> SearchAsynch(string query)
{
DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null);
var results = await Task.Factory.FromAsync(webQuery.BeginExecute(null, null)
, asyncResult=> webQuery.EndExecute(asyncResult));
Console.WriteLine("Hi there");
return results;
}
我不太熟悉Bing API,但如果API不包含异步方法,您可以通过将调用包装在启动的Task
中来实现异步。async
修饰符不会使你的方法自动异步,它只允许在内部await
其他异步方法。
所以,在你的情况下,这可能是最简单的:
public Task<IEnumerable<WebResult>> SearchAsync(string query)
{
if (query == null)
{
throw new ArgumentNullException("query cannot be null");
}
return Task.Run(() =>
{
DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null);
return webQuery.Execute();
}
}
然后你可以把这个方法await
标记为其他方法async
:
var result = await SearchAsync("yourQuery");
如果Bing API有async方法对Begin/End
,你可以使用Task.Factory.FromAsync
从async方法对创建任务。Servy的回答更详细。
按MSDN
通常,由async关键字修改的方法至少包含一个等待表达式或声明。该方法同步运行,直到它到达第一个await表达式。此时,它被挂起,直到等待的任务完成。与此同时,控件返回给该方法的调用者。如果该方法不包含await表达式或语句,然后同步执行。编译器警告提醒您任何不包含await的异步方法,因为这种情况可能表示错误。有关详细信息,请参见编译器警告(级别1)CS4014。
编辑:我想我应该补充这一点,但它已经在这篇文章的评论部分了。标记为async
的方法在遇到await
关键字之前实际上不会运行异步。
这是一个在独立项目中使用async的例子。
private async void button2_Click(object sender, EventArgs e)
{
DataTable dtMessages = await getMessages2(string sqlConn2, nMessage);
}
public async Task<DataTable> getMessages2(string sqlConn, int n)
{
//create your query and command
var o = await cmd2.ExecuteReaderAsync();
DataTable dtMessages = o;
return dtMessages;
}
这个警告只是告诉你,无论你在哪里调用SearchAsynch,它都需要在它之前有await。
var result = await SearchAsynch(query);
然而,SearchAsynch并没有像其他人所说的那样正确实现。