我有一个简单的Winforms应用程序。我想后台执行TCP连接/打印请求,并在代码中的设定点检查所有任务的输出。
我希望ReportOnTasks
会阻塞,直到WaitAll
完成为止。请有人能解释为什么不是这种情况吗?我还担心我的结构不正确。
编辑,以阐明我的意图: 我想在收到数据后立即发送打印作业。然后继续执行其他一些DB操作。完成所有打印操作后,我想更新UI来说明结果。
我已经尽力简化了代码。也许太多了。 HomeController只是初始化一些东西。表单和文件监视程序上有一些按钮可以触发主要功能。
public class HomeController
{
public HomeController(){
MessageBox.Show("1");
oPrintController.PrintAsync("192.168.2.213", Encoding.ASCII.GetBytes("string to print"));
MessageBox.Show("2");
// Block here untill tasks are complete
ReportOnTasks();
MessageBox.Show("Report on tasks complete");
}
public async void ReportOnTasks()
{
await Task.WhenAll(oPrintController.Tasks);
foreach(Task<PrintController.PrintResult> PR in oPrintController.Tasks)
{
// do something with the result of task
}
}
}
和PrintController
public class PrintController
{
public List<Task<PrintResult>> Tasks = new List<Task<PrintResult>>();
public async void PrintAsync(string sIP, List<byte[]> lsToPrint, int iPort = 9100)
{
var s = await Task.Run(() => PrintAsync1(sIP, lsToPrint));
}
public async System.Threading.Tasks.Task<PrintResult> PrintAsync1(string sIP, List<byte[]> lsToPrint, int iPort = 9100)
{
using (TcpClient tc = new TcpClient())
{
await tc.ConnectAsync(sIP, iPort);
using (var ns = tc.GetStream())
{
foreach (byte[] btLabel in lsToPrint)
{
await ns.WriteAsync(btLabel, 0, btLabel.Length);
}
}
}
Thread.Sleep(10000);
return new PrintResult();
}
}
public class PrintResult
{
bool bSuccess = false;
}
答案 0 :(得分:4)
您不是await
拨打ReportOnTasks()
的电话
而且,您不能在ctor中await
,因为它们不能异步。
根据HomeController
的使用方式,您可以使用静态异步方法,该方法返回由私有ctor创建的HomeController
的实例:
类似这样的东西:
public class HomeController
{
//notice private - you can't new up a HomeController - you have to use `CreateInstance`
private HomeController(){
MessageBox.Show("1");
//not clear from your code where oPrintController comes from??
oPrintController.PrintAsync("192.168.2.213", Encoding.ASCII.GetBytes("string to print"));
MessageBox.Show("2");
MessageBox.Show("Report on tasks complete");
}
public static async Task<HomeController> CreateInstance() {
var homeController = new HomeController();
await homeController.ReportOnTasks();
return homeController;
}
//don't use async void! Change to Task
public async Task ReportOnTasks()
{
//not clear from your code where oPrintController comes from??
await Task.WhenAll(oPrintController.Tasks);
foreach(Task<PrintController.PrintResult> PR in oPrintController.Tasks)
{
// do something with the result of task
}
}
}
用法:
var homeControllerInstance = await HomeController.CreateInstance();
答案 1 :(得分:0)
通常不建议在类构造函数中执行繁重的操作,但是我想您不会更改该部分,因此为了等待ReportOnTasks
完成,您需要使其同步。
请注意,构造函数本身不支持异步/等待,因此无法将其标记为async
。
话虽如此,您不会真正将void ReportOnTasks
标记为async
来提高性能。此外,由于异常处理方面的问题,通常不可行,因此不建议将void
方法标记为async
。
因此,您可以像Alex所示的那样推迟ReportOnTasks
,也可以同步等待所有任务完成(这可以在ctor中完成)。
public void ReportOnTasks()
{
Task.WhenAll(oPrintController.Tasks).GetAwaiter().GetResult(); //synchronously wait
foreach(Task<PrintController.PrintResult> PR in oPrintController.Tasks)
{
// do something with the result of task
}
}
但是,我不建议采用这种方法,因为实例创建将花费一些时间,最重要的是会阻塞UI线程-这通常表明某些东西真的很腥