C#多线程之异步编程

时间:2022-11-11 08:14:20

c#中异步编程,主要有两种方法: 1、委托的异步调用; 2、Task的await,async (c# 4.5)

我们来看例子:

         /// <summary>
/// 异步保存网页,url:网页地址,path:要保存的位置
/// </summary>
private void SavePageAsync(string url, string path)
{
Func<string, string, bool> fun = SavePageSingleFile;
IAsyncResult result = fun.BeginInvoke(url, path, new AsyncCallback(SavePageCompleted), null);
}

Func,是系统定义好的委托类型,当然也可以自定义委托了,委托的本质是一个类,它有一个BeginInvoke 异步调用方法。SavePageSingleFile方法是委托要执行的方法:

         private bool SavePageSingleFile(string url, string path)
{
bool result = false;
try
{
CDO.Message message = new CDO.MessageClass();
ADODB.Stream stream = null;
message.MimeFormatted = true;
message.CreateMHTMLBody(url, CDO.CdoMHTMLFlags.cdoSuppressNone, "", "");
stream = message.GetStream();
stream.SaveToFile(path, ADODB.SaveOptionsEnum.adSaveCreateOverWrite);
message = null;
stream.Close(); result = true;
}
catch (Exception ex)
{
Logger.Debug("保存文件出错:" + ex.Message);
}
return result;
}
  
委托任务完成后的回调方法 SavePageCompleted:
       private void SavePageCompleted(IAsyncResult result)
{
try
{
var handler = (Func<string, string, bool>)((AsyncResult)result).AsyncDelegate;
var r = handler.EndInvoke(result); this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
this.Opacity = ; if (CloseWaittingWindow != null)
{
CloseWaittingWindow();
}
this.Cursor = System.Windows.Input.Cursors.Hand; MessageTip tip = new MessageTip();
if (r)
{
tip.Show("保存网页", "文件保存成功");
}
else
{
tip.Show("保存网页", "文件保存失败");
}
}
);
}
catch (Exception ex)
{
Logger.Debug("保存页面文件出错:" + ex.Message);
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
new MessageTip().Show("保存网页", "文件保存出错");
this.Opacity = ; if (CloseWaittingWindow != null)
{
CloseWaittingWindow();
}
this.Cursor = System.Windows.Input.Cursors.Hand;
}
);
}
}

最后看下 SavePageAsync 方法的调用:

         /// <summary>
/// 保存当前页面
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSavePage_Click(object sender, RoutedEventArgs e)
{
if (this.DBVisitViewModel.CanSavePageExcute)
{
string url = this.WebPageBrower.Url.AbsoluteUri;
if (!Tool.CheckUrl(url))
{
new MessageTip().Show("保存页面", "当前页面无法保存");
return;
} SaveFileDialog sfd = new SaveFileDialog(); sfd.InitialDirectory = @"D:\";
sfd.Filter = "mht file|*.mht"; if (sfd.ShowDialog() == DialogResult.OK)
{
if (OpenWaittingWindow != null)
{
this.Cursor = System.Windows.Input.Cursors.Wait;
SavePageAsync(url, sfd.FileName); this.Opacity = 0.8;
OpenWaittingWindow("正在保存网页,请稍等...");
}
}
}
}

在framework 4.0的时候,委托异步调用显得很方便,到了4.5的时候,我们可以用Task实现异步调用。改下上面的例子:

        private async void SavePageAsync(string url, string path)
{
var r = await SavePageSingleFile(url, path); try
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
this.Opacity = ; if (CloseWaittingWindow != null)
{
CloseWaittingWindow();
}
this.Cursor = System.Windows.Input.Cursors.Hand; MessageTip tip = new MessageTip();
if (r)
{
tip.Show("保存网页", "文件保存成功");
}
else
{
tip.Show("保存网页", "文件保存失败");
}
}
);
}
catch (Exception ex)
{
Logger.Debug("保存页面文件出错:" + ex.Message);
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
new MessageTip().Show("保存网页", "文件保存出错");
this.Opacity = ; if (CloseWaittingWindow != null)
{
CloseWaittingWindow();
}
this.Cursor = System.Windows.Input.Cursors.Hand;
}
);
} }
static async Task<bool> SavePageSingleFile(string url, string path)
{
return await Task.Run(() =>
{
bool result = false;
try
{
CDO.Message message = new CDO.MessageClass();
ADODB.Stream stream = null;
message.MimeFormatted = true;
message.CreateMHTMLBody(url, CDO.CdoMHTMLFlags.cdoSuppressNone, "", "");
stream = message.GetStream();
stream.SaveToFile(path, ADODB.SaveOptionsEnum.adSaveCreateOverWrite);
message = null;
stream.Close(); result = true;
}
catch (Exception ex)
{
Logger.Debug("保存文件出错:" + ex.Message);
}
return result;
});
}

第5行后的try,catch语句块,就是保存网页后的回调,它的执行是在子线程中,因此,在wpf 中要用 Dispatcher(回调中牵扯到对页面的操作)。为了简化这一例子,我这儿给出一个简单的可以执行的例子:

   static void Main(string[] args)
{
Add(,);
Console.WriteLine("主线程:" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("main Thread go on sth");
Console.Read();
} private async static void Add(int x, int y)
{
Console.WriteLine("主线程:" + Thread.CurrentThread.ManagedThreadId);
var t = await TestAsync(x,y);
Console.WriteLine("正在等待完成任务,当前线程:"+Thread.CurrentThread.ManagedThreadId);  Console.WriteLine("运行结果:" + t);
}
static async Task<int> TestAsync(int x, int y)
{
return await Task.Run(() =>
{
Thread.Sleep();
Console.WriteLine("子线程:" + Thread.CurrentThread.ManagedThreadId);
return x + y;
});
}

运行结果:

C#多线程之异步编程

异步编程主要是为了解决耗时的任务占用主线程的问题,比如ajax的异步调用,不会导致页面卡死。好了,今天就谈到这里,该吃中午饭了。