日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

winform什么时候会调用closed事件_async/await 给程序带来了什么?

發布時間:2023/12/2 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 winform什么时候会调用closed事件_async/await 给程序带来了什么? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

如果說async給ASP.NET帶來的是處理能力的提高,那么在WinForm中給程序員帶來的好處則是最大的。我們再也不用因為要實現異步寫回調或者綁定事件了,省事了,可讀性也提高了。不信你看下面我們將調用我們那個web service的代碼在.NET4.5下實現一下:

1

2

3

4

5

6

7

private?async?void?button2_Click(object?sender, EventArgs e)

{

????var?pageContent =?new?localhost.PageContentSoapClient();

????var?content = await pageContent.DownloadContentAsync("http://jesse2013.cnblogs.com");

????textBox1.Text = content.Body.DownloadContentResult;

}

  簡單的三行代碼,像寫同步代碼一樣寫異步代碼,我想也許這就是async/await的魔力吧。在await之后,UI線程就可以回去響應UI了,在上面的代碼中我們是沒有新線程產生的,和EAP一樣拿到結果直接就可以對UI操作了。

  async/await似乎真的很好,但是如果我們await后面的代碼執行在另外一個線程中會發生什么事情呢?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

private?async?void?button1_Click(object?sender, EventArgs e)

{

????label1.Text =?"Calculating Sqrt of 5000000";

????button1.Enabled =?false;

????progressBar1.Visible =?true;

????double?sqrt = await Task<double>.Run(() =>

????{

????????double?result = 0;

????????for?(int?i = 0; i < 50000000; i++)

????????{

????????????result += Math.Sqrt(i);

????????????progressBar1.Maximum = 50000000;

????????????progressBar1.Value = i;

????????}

????????return?result;

????});

????progressBar1.Visible =?false;

????button1.Enabled =?true;

????label1.Text =?"The sqrt of 50000000 is "?+ sqrt;

}

  我們在界面中放了一個ProgressBar,同時開一個線程去把從1到5000000的平方全部加起來,看起來是一個非常耗時的操作,于是我們用Task.Run開了一個新的線程去執行。(注:如果是純運算的操作,多線程操作對性能沒有多大幫助,我們這里主要是想給UI一個進度顯示當前進行到哪一步了。)看起來沒有什么問題,我們按F5運行吧!
  Bomb~

  當執行到這里的時候,程序就崩潰了,告訴我們”無效操作,只能從創建porgressBar的線程訪問它。“ ?這也是我們一開始提到的,在WinForm程序中,只有UI主線程才能對UI進行操作,其它的線程是沒有權限的。接下來我們就來看看,如果在WinForm中實現非UI線程對UI控制的更新操作。?

萬能的Invoke

  WinForm中絕大多數的控件包括窗體在內都實現了Invoke方法,可以傳入一個Delegate,這個Delegate將會被擁有那個控制的線程所調用,從而避免了跨線程訪問的問題。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

Trace.TraceInformation("UI Thread : {0}", Thread.CurrentThread.ManagedThreadId);

double?sqrt = await Task<double>.Run(() =>

{

????Trace.TraceInformation("Run calculation on thread: {0}", Thread.CurrentThread.ManagedThreadId);

????double?result = 0;

????for?(int?i = 0; i < 50000000; i++)

????{

????????result += Math.Sqrt(i);

????????progressBar1.Invoke(new?Action(() => {

????????????Trace.TraceInformation("Update UI on thread: {0}", Thread.CurrentThread.ManagedThreadId);

????????????progressBar1.Maximum = 50000000;

????????????progressBar1.Value = i;

????????}));

????}

????return?result;

});

  Desktop.vshost.exe Information: 0 : UI Thread : 9  Desktop.vshost.exe Information: 0 : Run calculation on thread: 10  Desktop.vshost.exe Information: 0 : Update UI on thread: 9

  Invoke方法比較簡單,我們就不做過多的研究了,但是我們要考慮到一點,Invoke是WinForm實現的UI跨線程溝通方式,WPF用的卻是Dispatcher,如果是在ASP.NET下跨線程之間的同步又怎么辦呢。為了兼容各種技術平臺下,跨線程同步的問題,Microsoft在.NET2.0的時候就引入了我們下面的這個對象。

SynchronizationContext上下文同步對象

為什么需要SynchronizationContext

  就像我們在WinForm中遇到的問題一樣,有時候我們需要在一個線程中傳遞一些數據或者做一些操作到另一個線程。但是在絕大多數情況下這是不允許的,出于安全因素的考慮,每一個線程都有它獨立的內存空間和上下文。因此在.NET2.0,微軟推出了SynchronizationContext。

  它主要的功能之一是為我們提供了一種將一些工作任務(Delegate)以隊列的方式存儲在一個上下文對象中,然后把這些上下文對象關聯到具體的線程上,當然有時候多個線程也可以關聯到同一個SynchronizationContext對象。獲取當前線程的同步上下文對象可以使用SynchronizationContext.Current。同時它還為我們提供以下兩個方法Post和Send,分別是以異步和同步的方法將我們上面說的工作任務放到我們SynchronizationContext的隊列中。

SynchronizationContext示例

  還是拿我們上面Invoke中用到的例子舉例,只是這次我們不直接調用控件的Invoke方法去更新它,而是寫了一個Report的方法專門去更新UI。

1

2

3

4

5

6

7

8

9

10

11

12

double?sqrt = await Task<double>.Run(() =>

{

????Trace.TraceInformation("Current thread id is:{0}", Thread.CurrentThread.ManagedThreadId);

????double?result = 0;

????for?(int?i = 0; i < 50000000; i++)

????{

????????result += Math.Sqrt(i);

????????Report(new?Tuple<int,?int>(50000000, i));

????}

????return?result;

});

  每一次操作完之后我們調用一下Report方法,把我們總共要算的數字,以及當前正在計算的數字傳給它就可以了。接下來就看我們的Report方法了。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

private?SynchronizationContext m_SynchronizationContext;

private?DateTime m_PreviousTime = DateTime.Now;

public?Form1()

{

????InitializeComponent();

????// 在全局保存當前UI線程的SynchronizationContext對象

????m_SynchronizationContext = SynchronizationContext.Current;

}

public?void?Report(Tuple<int,?int> value)

{

????DateTime now = DateTime.Now;

????if?((now - m_PreviousTime).Milliseconds > 100)

????{

????????m_SynchronizationContext.Post((obj) =>

????????{

????????????Tuple<int,?int> minMax = (Tuple<int,?int>)obj;

????????????progressBar1.Maximum = minMax.Item1;

????????????progressBar1.Value = minMax.Item2;

????????}, value);

????????m_PreviousTime = now;

????}

}

  整個操作看起來要比Inovke復雜一點,與Invoke不同的是SynchronizationContext不需要對Control的引用,而Invoke必須先得有那個控件才能調用它的Invoke方法對它進行操作。

總結

以上是生活随笔為你收集整理的winform什么时候会调用closed事件_async/await 给程序带来了什么?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。