static void Main(string[] args) { Console.WriteLine("main thread started.."); getUserMoves("me@hotmail.com", "password"); getUserMoviesTaskAsync("me@hotmail.com","password"); Console.WriteLine("waiting for main thread to end"); Console.ReadLine(); } private static void getUserMoves(string email, string password) { WebClient wb = new WebClient(); string userRight = wb.DownloadString(email + password); string moviesUserCanWatch = wb.DownloadString(userRight); Console.WriteLine(moviesUserCanWatch); } private static async void getUserMoviesTaskAsync(string email, string password) { WebClient wb = new WebClient(); string userRight = await wb.DownloadStringTaskAsync(email + password); string moviesUserCanWatch = await wb.DownloadStringTaskAsync(userRight); Console.WriteLine(moviesUserCanWatch); }第一个
getUserMoves("me@hotmail.com", "password");是同步代码,也就是说除非里面所有步骤都执行完毕,否则主线程会被block,你永远也看不到“waiting for main thread to end”
getUserMoviesTaskAsync("me@hotmail.com","password");是异步代码,程序会输出:
<Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Grid> <Button Content="Button" HorizontalAlignment="Left" Margin="34,30,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1" x:Name="buton1"/> <TextBlock HorizontalAlignment="Left" Margin="58,90,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" x:Name="textBlock1"/> </Grid> </Window>
Code Behind:
private void Button_Click_1(object sender, RoutedEventArgs e) { this.textBlock1.Text = "hello world!"; }
private void Button_Click_1(object sender, RoutedEventArgs e) { Task.Factory.StartNew(() => this.textBlock1.Text = "hello world!"); }
private void Button_Click_1(object sender, RoutedEventArgs e) { Task.Factory.StartNew(() => this.buton1.Dispatcher.BeginInvoke(new Action(() => this.textBlock1.Text = "hello world!"))); }
<Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <StackPanel> <Button Content="Go to Rolia, Normal Async Usage" x:Name="butonNormalAsync" Click="butonNormalAsync_Click"/> <Button Content="Go to Rolia, Async + Await" x:Name="buttonAsyncAwait" Click="buttonAsyncAwait_Click"/> <TextBox x:Name="textBlock1" Height="200" TextWrapping="Wrap" ScrollViewer.HorizontalScrollBarVisibility="Visible"/> </StackPanel> </Window>
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace WpfApplication1 { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } string baseForumURI = "http://www.rolia.net"; // 论坛入口的URI string forumEntryURI; // should be http://www.rolia.net/f // 论坛URI string scienceForumEntryURI; // 科技领域杂谈的URI string firstThreadURL; // 我的第一篇帖子的URI string htmlString; // 传统的异步方式,就一个字:乱 private void butonNormalAsync_Click(object sender, RoutedEventArgs e) { WebClient wc = new WebClient(); wc.DownloadDataCompleted += (s, e1) => { htmlString = System.Text.Encoding.GetEncoding("UTF-8").GetString(e1.Result); forumEntryURI = getForumEntryURI(htmlString); WebClient wc1 = new WebClient(); wc1.DownloadDataCompleted += (s2, e2) => { htmlString = System.Text.Encoding.GetEncoding("UTF-8").GetString(e2.Result); scienceForumEntryURI = getScientForumEntry(htmlString); WebClient wc2 = new WebClient(); wc2.DownloadDataCompleted += (s3, e3) => { htmlString = System.Text.Encoding.GetEncoding("UTF-8").GetString(e3.Result); firstThreadURL = getFirstThreadURL(htmlString); //ok now, we came to the last step: show the content of my thread WebClient wc3 = new WebClient(); wc3.DownloadDataCompleted += (s4, e4) => { htmlString = System.Text.Encoding.GetEncoding("UTF-8").GetString(e4.Result); buttonAsyncAwait.Dispatcher.BeginInvoke(new Action(() => textBlock1.Text = htmlString)); }; //从我的第一篇帖子的URI download content wc3.DownloadDataAsync(new Uri(firstThreadURL)); }; // step 3: 从“科技领域杂谈” 找到我的第一篇帖子 wc2.DownloadDataAsync(new Uri(scienceForumEntryURI)); }; // step 2: 从论坛列表找到“科技领域杂谈” wc1.DownloadDataAsync(new Uri(forumEntryURI)); }; // step 1: 从rolia.net找到论坛入口 wc.DownloadDataAsync(new Uri(baseForumURI)); } // Async + Await 异步方式 private async void buttonAsyncAwait_Click(object sender, RoutedEventArgs e) { WebClient wc = new WebClient(); // step 1: 从rolia.net找到论坛入口 byte[] resultBytes = await wc.DownloadDataTaskAsync(baseForumURI); htmlString = System.Text.Encoding.GetEncoding("UTF-8").GetString(resultBytes); forumEntryURI = getForumEntryURI(htmlString); // step 2: 从论坛列表找到“科技领域杂谈” resultBytes = await wc.DownloadDataTaskAsync(forumEntryURI); htmlString = System.Text.Encoding.GetEncoding("UTF-8").GetString(resultBytes); scienceForumEntryURI = getScientForumEntry(htmlString); // step 3: 从“科技领域杂谈” 找到我的第一篇帖子 resultBytes = await wc.DownloadDataTaskAsync(scienceForumEntryURI); htmlString = System.Text.Encoding.GetEncoding("UTF-8").GetString(resultBytes); firstThreadURL = getFirstThreadURL(htmlString); //从我的第一篇帖子的URI download content resultBytes = await wc.DownloadDataTaskAsync(firstThreadURL); htmlString = System.Text.Encoding.GetEncoding("UTF-8").GetString(resultBytes); // show the raw content of my thread in the textBox textBlock1.Text = htmlString; } // parse HTML to ForumEntryURI string getForumEntryURI(string htmlString) { int index1 = htmlString.IndexOf("枫下论坛"); int index2 = htmlString.Substring(0,index1).LastIndexOf(@"<a"); string result = htmlString.Substring(index2, index1 - index2); result = result.Split(' ').First(s => s.Contains("href")).TrimEnd('>','\n','\t').Split('=').Last().Trim('\"'); return string.Format("{0}{1}",baseForumURI, result); } // parse HTML to ScientForumEntry private string getScientForumEntry(string htmlString) { int index1 = htmlString.IndexOf("科技领域杂谈"); int index2 = htmlString.Substring(0, index1).LastIndexOf(@"<a"); string result = htmlString.Substring(index2, index1 - index2); result = result.Split(' ').First(s => s.Contains("href")).Substring("href=".Length).Trim('\''); return string.Format("{0}/{1}", forumEntryURI, result); } // parse HTML to FirstThreadURL private string getFirstThreadURL(string htmlString) { int index1 = htmlString.IndexOf("binghongcha76"); index1 = htmlString.Substring(0, index1).LastIndexOf(@"<a"); int index2 = htmlString.Substring(0, index1).LastIndexOf(@"<a"); string result = htmlString.Substring(index2, index1 - index2); result = result.Split(' ').First(s => s.Contains("href")).Substring("href=".Length).Trim('\''); return string.Format("{0}/{1}", forumEntryURI, result); } } }
static void Main(string[] args) { Console.WriteLine("main thread started.."); getUserMoves("me@hotmail.com", "password"); getUserMoviesTaskAsync("me@hotmail.com","password"); Console.WriteLine("waiting for main thread to end"); int n = 1; while(true) { Console.WriteLine(GetCurrentThreadId() + ": n= " + n); n=n+1; } } private static async void getUserMoviesTaskAsync(string email, string password) { WebClient wb = new WebClient(); string userRight = await wb.DownloadStringTaskAsync(email + password); Console.WriteLine(GetCurrentThreadId() + " first await finished, about to run next one"); string moviesUserCanWatch = await wb.DownloadStringTaskAsync(userRight); Console.WriteLine(moviesUserCanWatch); }“一旦遇到await关键字...把运行权交还给调用getUserMoviesTaskAsync函数的Object,在这里,就是Main(string[] args) {}”的具体意思是什么?比如说main正在原始线程中执行一个循环;.net在工作线程完成getUserMoviesTaskAsync,它怎样把控制权交给main?在控制台会看到什么?getUserMoviesTaskAsync中的Console.WriteLine打印出的线程id是哪一个线程的?