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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

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

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線程就可以回去響應(yīng)UI了,在上面的代碼中我們是沒有新線程產(chǎn)生的,和EAP一樣拿到結(jié)果直接就可以對UI操作了。

  async/await似乎真的很好,但是如果我們await后面的代碼執(zhí)行在另外一個(gè)線程中會(huì)發(fā)生什么事情呢?

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;

}

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

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

萬能的Invoke

  WinForm中絕大多數(shù)的控件包括窗體在內(nèi)都實(shí)現(xiàn)了Invoke方法,可以傳入一個(gè)Delegate,這個(gè)Delegate將會(huì)被擁有那個(gè)控制的線程所調(diào)用,從而避免了跨線程訪問的問題。

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方法比較簡單,我們就不做過多的研究了,但是我們要考慮到一點(diǎn),Invoke是WinForm實(shí)現(xiàn)的UI跨線程溝通方式,WPF用的卻是Dispatcher,如果是在ASP.NET下跨線程之間的同步又怎么辦呢。為了兼容各種技術(shù)平臺(tái)下,跨線程同步的問題,Microsoft在.NET2.0的時(shí)候就引入了我們下面的這個(gè)對象。

SynchronizationContext上下文同步對象

為什么需要SynchronizationContext

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

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

SynchronizationContext示例

  還是拿我們上面Invoke中用到的例子舉例,只是這次我們不直接調(diào)用控件的Invoke方法去更新它,而是寫了一個(gè)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;

});

  每一次操作完之后我們調(diào)用一下Report方法,把我們總共要算的數(shù)字,以及當(dāng)前正在計(jì)算的數(shù)字傳給它就可以了。接下來就看我們的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();

????// 在全局保存當(dāng)前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;

????}

}

  整個(gè)操作看起來要比Inovke復(fù)雜一點(diǎn),與Invoke不同的是SynchronizationContext不需要對Control的引用,而Invoke必須先得有那個(gè)控件才能調(diào)用它的Invoke方法對它進(jìn)行操作。

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。