2014-09-11 93 views
0

我有一个方法void getInformation(),它调用5个其他方法,每个方法都从数据库获取一些数据。它需要大约1秒,直到收集所有数据并返回到getInformation(),并且因为我认为我应该在后台收集数据。我的问题是:我可以只制作getInformation()async,以便在其他方法正在收集信息时不会阻止用户界面,或者是否必须制作其他所有方法async了解异步方法

private void button_Click(object sender, EventArgs e) 
{ 
    await getContactInformation(); 
} 

public async Task getContactInformation() 
{ 
    this.data.Add(collectData1()); 
    this.data.Add(collectData2()); 
    this.data.Add(collectData3()); 
    this.data.Add(collectData4()); 
    this.data.Add(collectData5()); 
} 
+0

看看这个[教程](http://www.dotnetperls.com/async) – 2014-09-11 10:37:12

+1

看看这些问答:https://stackoverflow.com/questions/14177891/can-somebody-please-explain- async-await,https://stackoverflow.com/questions/10960998/how-different-async-programming-is-from-threads和https://stackoverflow.com/questions/14455293/async-and-await – Dirk 2014-09-11 10:43:42

回答

2

首先,async的理想情况是使用“异步一路”。在这种情况下,你的代码应该是这样的:

private async void button_Click(object sender, EventArgs e) 
{ 
    await getContactInformationAsync(); 
} 

public async Task getContactInformationAsync() 
{ 
    this.data.Add(await collectData1Async()); 
    this.data.Add(await collectData2Async()); 
    this.data.Add(await collectData3Async()); 
    this.data.Add(await collectData4Async()); 
    this.data.Add(await collectData5Async()); 
} 

需要注意的是现代数据库API,如实体框架6,ADO.NET时,SQLite等,都可以用它来实现collectDataNAsync方法异步的API 。这是理想的async方案,因为它可以最大限度地减少线程浪费并保持UI的良好响应。

但是,如果你想要更多的是“速战速决”,那么你就可以推(同步)调用开了一个后台线程,然后把这样的背景下异步工作,因为这样的:

private async void button_Click(object sender, EventArgs e) 
{ 
    await Task.Run(() => getContactInformation()); 
} 

public void getContactInformation() 
{ 
    this.data.Add(collectData1()); 
    this.data.Add(collectData2()); 
    this.data.Add(collectData3()); 
    this.data.Add(collectData4()); 
    this.data.Add(collectData5()); 
} 

这将以线程池线程为代价解决您的直接问题(释放UI线程)。这不是理想但它会工作。

+0

我使用的API不提供异步方法,但感谢您的建议 – user2414460 2014-09-11 12:59:30

2

一般来说,我会建议所有IO将采取关闭UI线程,但在使每一个单独的呼叫async没有意义的。

有关async对数据库IO阻塞线程调用的影响的指导,我发现这个非常明确和有用的建议。

http://blogs.msdn.com/b/rickandy/archive/2009/11/14/should-my-database-calls-be-asynchronous.aspx

+0

我认为在这种情况下,每次调用'async'都不是正确的解决方案,并且感谢您的链接 – user2414460 2014-09-11 12:00:01

2

号你的方法的身体已经使用的await,否则你会得到一个警告。

够简单。

总结你的方法体...

await Task.Run(()=>{ 
// do your thing 
}); 
+0

您的意思是在'// do your thing'应该是数据收集调用,我会好吗? – user2414460 2014-09-11 12:01:49

+0

是的。将其替换为您的普通同步代码以使其在单独的线程上运行。 – kidshaw 2014-09-11 14:34:19

+0

感谢@DanielKelley的编辑。从内存写入,可以使用factory.startnew代替运行。 – kidshaw 2014-09-11 14:36:05

1

目的异步任务是让它在后台执行不锁定主线程,比如做一个DownloadFileAsync。 基本思想是你有一个独立的线程池,异步执行任务。使用它时。然而,该对象承诺它会在某个时间执行操作并在请求时给出结果。这意味着当你请求结果并且没有完成时它会阻塞,否则在线程池中执行。

异步和同步之间唯一的区别是我们可以在异步方法启动后执行某些操作(如编写消息)。它避免了阻止控制流。声明继续如常。 异步和等待是一种代码模式 - 它们允许方法异步运行。它们使得使用线程的代码更易于阅读。这反过来又使得代码不太容易出现缺陷。

http://blogs.msdn.com/b/cdndevs/archive/2013/12/18/c-async-and-await-why-do-we-need-them-part-1.aspx

How and When to use `async` and `await`

最后

程序都充满了不立即返回的方法。有时,从网络来看,外部速度下降是原因,而不是处理器的使用。使用异步和等待,我们异步运行方法 - 线程是可选的。

1

我可以只做getInformation()异步,以便在其他方法正在收集信息时不阻止用户界面,或者是否必须使每个其他方法异步?

后者。当你去async它是“异步一路”,这意味着你使async方法调用一直到你的堆栈顶部。对于IO绑定操作,不需要使用后台线程,因为现在大多数API都暴露了XXXAsync真正异步的方法调用,这意味着您的UI消息循环可以在IO请求执行时自由处理其他消息。

但需要注意的一点很重要,即标记方法async不足以使其异步。您实际上必须为await进行异步操作,例如您的数据库方法调用。如果没有异步API调用数据库,您将无法进行异步。

在你的情况下,getContactInformation会让编译器忽略警告,说你有一个未被等待的异步方法。事实上,如果你await getInformation(),你将会完全同步运行。

+0

但是,如果我想使数据收集调用“异步”,我将不得不改变我的整个项目。这段代码只是想知道如何得到这个解决方案 – user2414460 2014-09-11 12:05:53

+0

解决方案是让你的数据收集调用“异步”。这是主要的一点。如果你的数据库调用是同步的,你希望如何使它们异步? – 2014-09-11 12:21:28

+0

我希望有一个解决方案,我不需要改变所有方法体和头文件,就像'BackgroundClass.doInBackground(methodCall)',这使得UI响应,但仍然执行被调用的方法。 – user2414460 2014-09-11 12:26:52