I have been using Asynchronous operations in my WinForms client since the beginning, but only for some operations. When the ExecuteReader
or the ExecuteNonQuery
completes, the callback delegate fires and everything works just fine.
我从一开始就在WinForms客户端中使用异步操作,但仅限于某些操作。当ExecuteReader或ExecuteNonQuery完成时,回调委托会触发,一切正常。
I've basically got two issues:
我基本上有两个问题:
1) What is the best structure for dealing with this in a real-life system? All the examples I have seen are toy examples where the form handles the operation completion and then opening a datareader on the EndExecuteReader
. Of course, this means that the form is more tightly coupled to the database than you would normally like. And, of course, the form can always easily call .Invoke
on itself. I've set up all my async objects to inherit from a AsyncCtrlBlock<T>
class and have the form and all the callback delegates provided to the constructor of the async objects in my DAL.
1)在现实生活系统中处理这个问题的最佳结构是什么?我看到的所有示例都是玩具示例,其中表单处理操作完成,然后在EndExecuteReader上打开datareader。当然,这意味着表单与数据库的关联程度比您通常所希望的更紧密。而且,当然,表单总是可以轻松调用。自我调用。我已经设置了所有异步对象以从AsyncCtrlBlock
2) I am going to re-visit a portion of the program that currently is not async. It makes two calls in series. When the first is complete, part of the model can be populated. When the second is complete, the remaining part of the model can be completed - but only if the first part is already done. What is the best way to structure this? It would be great if the first read can be done and the processing due to the first read be underway while the second is launched, but I don't want the processing of the second read to be started until I know that the processing of the first read's data has been completed.
2)我将重新访问当前不是异步的程序的一部分。它会串联两个电话。第一个完成后,可以填充部分模型。当第二个完成时,模型的剩余部分可以完成 - 但仅当第一部分已经完成时。构建这个的最佳方法是什么?如果可以完成第一次读取并且第二次读取时第一次读取的处理正在进行中,那将是很好的,但我不希望第二次读取的处理开始,直到我知道处理第一次读取的数据已经完成。
2 个解决方案
#1
regarding 2)
make the first phase of your model populating asynchronous. you will have something like that
使模型的第一阶段填充异步。你会有类似的东西
FisrtCall();
AsyncResult arPh1 = BeginPhaseOne(); //use results from first call
SecondCall();
EndPhaseOne(arPh1); //wait until phase one is finished
PhaseTwo(); //proceed to phase two
#2
If you are on .Net 4, this would be an ideal application of TPL! You could factor your code into tasks like this:
如果您使用.Net 4,这将是TPL的理想应用!您可以将代码分解为如下任务:
TaskScheduler uiScheduler = GetUISheduller();
SqlCommand command1 = CreateCommand1();
Task<SqlDataReader> query1 = Task<SqlDataReader>.Factory.FromAsync(command1.BeginExecuteReader, command1.EndExecuteReader, null);
query1.ContinueWith(t => PopulateGrid1(t.Result), uiScheduler);
SqlCommand command2 = CreateCommand2();
query1.ContinueWith(t => Task<SqlDataReader>.Factory.FromAsync(command2.BeginExecuteReader, command2.EndExecuteReader, null)
.ContinueWith(t => PopulateGrid2(t.Result), uiScheduler);
#1
regarding 2)
make the first phase of your model populating asynchronous. you will have something like that
使模型的第一阶段填充异步。你会有类似的东西
FisrtCall();
AsyncResult arPh1 = BeginPhaseOne(); //use results from first call
SecondCall();
EndPhaseOne(arPh1); //wait until phase one is finished
PhaseTwo(); //proceed to phase two
#2
If you are on .Net 4, this would be an ideal application of TPL! You could factor your code into tasks like this:
如果您使用.Net 4,这将是TPL的理想应用!您可以将代码分解为如下任务:
TaskScheduler uiScheduler = GetUISheduller();
SqlCommand command1 = CreateCommand1();
Task<SqlDataReader> query1 = Task<SqlDataReader>.Factory.FromAsync(command1.BeginExecuteReader, command1.EndExecuteReader, null);
query1.ContinueWith(t => PopulateGrid1(t.Result), uiScheduler);
SqlCommand command2 = CreateCommand2();
query1.ContinueWith(t => Task<SqlDataReader>.Factory.FromAsync(command2.BeginExecuteReader, command2.EndExecuteReader, null)
.ContinueWith(t => PopulateGrid2(t.Result), uiScheduler);