欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

.NET并發(fā)編程之函數(shù)閉包

 更新時(shí)間:2021年02月09日 21:39:38   作者:還俗和尚  
這篇文章主要介紹了.NET并發(fā)編程之函數(shù)閉包,有對(duì)于這方面不太懂的同學(xué)可以研究下

函數(shù)式編程

一個(gè)函數(shù)輸出當(dāng)做另一個(gè)函數(shù)輸入。有時(shí)候一個(gè)復(fù)雜問題,我們拆分成很多個(gè)步驟函數(shù),這些函數(shù)組合起來調(diào)用解決一個(gè)復(fù)雜問題。

在C#中不支持函數(shù)組合,但可以直接像這樣調(diào)用B(A(n)),這也是函數(shù)組合,但這不利于閱讀,人們習(xí)慣從左往右閱讀,而不是相反的方向。通過創(chuàng)建擴(kuò)展方法可以任何組合兩個(gè)函數(shù),像下面這樣

Func<A,C> Compose<A,B,C>(this Func<A.B> f ,Func<B,C> g)=>(n)=>g(f(n))

上述代碼為泛型委托Func<a,b>創(chuàng)建了一個(gè)擴(kuò)展Compose的擴(kuò)展方法,以泛型委托Func<b,c>為輸入?yún)?shù),返回組合后的函數(shù)Func<a,c>。創(chuàng)建一個(gè)高階函數(shù)Compose把不利于閱讀的隱藏起來。

在F#中就非常方便的使用函數(shù)組合。舉個(gè)例子,將一個(gè)列表中數(shù)字增加4再乘以3,構(gòu)建這兩個(gè)步驟的函數(shù)(當(dāng)然利用C#linq或F#map可以直接(x+4)*3,這里主要演示兩個(gè)功能函數(shù)如何組合起來)。

letadd4x=x+4
letmulitply3x=x*3
letlist=[0..10]
letnewList=List.map(funx->mulitply3(add4(x)))list
letnewList2=list|>List.map(add4>>mulitply3

在F#中使用>>中綴運(yùn)算符來使函數(shù)組合可以從左到右閱讀,更加精煉、簡(jiǎn)潔。

閉包的應(yīng)用

閉包可以讓函數(shù)訪問其所在的外部函數(shù)中的參數(shù)和變量,即使在其外部函數(shù)被返回之后。在js中經(jīng)常會(huì)出現(xiàn)閉包的場(chǎng)景,在C#和F#中,編譯器使用閉包來增加和擴(kuò)展變量的范圍。

C#在.NET2.0后引入閉包。在lambda和匿名方法中得到充分的使用。像下面的匿名函數(shù)引用變量a,訪問和管理變量a的狀態(tài)。如果不用閉包,就需要額外創(chuàng)建一個(gè)類函數(shù)來調(diào)用。

strings="freevariable";
Func<string,string>lambda=value=>a+""+value;

以下載圖片更新窗體PictureBox控件為例:

void UpdateImage(string url)
{
  System.Windows.Forms.PictureBox picbox = this.pictureBox1;
  var client = new WebClient();
  client.DownloadDataCompleted += (o, e) =>
    {
      if (picbox != null)
      {
        using (var ms = new MemoryStream(e.Result))
        {
          picbox.Image = Image.FromStream(ms);
        }
      }
    };
  client.DownloadDataAsync(new Uri(url));
  //picbox = null;
}

因?yàn)槭钱惒较螺d,UPdateImage方法返回后,圖片還未下載完成,但picbox變量仍然可以使用。這就是變量捕獲。lambda表達(dá)式捕獲了局部變量image,因此它仍停留在作用域中。但捕獲的變量值是在運(yùn)行時(shí)確定的,而不是在捕獲時(shí),最后一句如果放開,將不能更新窗體。運(yùn)行時(shí)picbox為null了,在F#中不存在null的概念,所以也不會(huì)出現(xiàn)此類錯(cuò)誤。

多線程環(huán)境中的閉包使用。猜測(cè)下面的代碼運(yùn)行結(jié)果如何?

for (int i = 1; i < 10; i++)
{
  Task.Factory.StartNew(()=>Console.WriteLine("{0}-{1}",
    Thread.CurrentThread.ManagedThreadId,i));
}

不會(huì)按期望的那樣打印1-9,因?yàn)樗麄児蚕碜兞縤,調(diào)用時(shí)i的值可能已經(jīng)被循環(huán)修改了。印證上面說的捕獲的變量值是在運(yùn)行時(shí)確定的。

這種情況就很難搞,給并行編程帶來了頭疼的問題,變量可變,這不廢話嗎,變量不會(huì)變就不叫變量了。在C#中解決此類問題的一個(gè)方法就是為每個(gè)任務(wù)創(chuàng)建創(chuàng)建和捕獲一個(gè)新的臨時(shí)變量,這樣它就能保留捕獲時(shí)的值。在F#中不存在這個(gè)問題,它的For循環(huán)每次創(chuàng)建一個(gè)新的不可變值。

記憶化函數(shù)緩存

一些函數(shù)會(huì)頻繁的使用相同的參數(shù)去調(diào)用。我們可以將用相同的參數(shù)調(diào)用函數(shù)的結(jié)果存儲(chǔ)起來,以便下次調(diào)用直接返回結(jié)果。例如對(duì)圖片每個(gè)像素做處理,一張圖片可能相同像素的會(huì)有很多,通過緩存可以直接返回上次計(jì)算結(jié)果。

//簡(jiǎn)單的函數(shù)緩存
public static Func<T, R> Memoize<T, R>(Func<T, R> func) where T : IComparable 
{
  Dictionary<T, R> cache = new Dictionary<T, R>();  
  return arg =>                    
  {
    if (cache.ContainsKey(arg))           
      return cache[arg];             
    return (cache[arg] = func(arg));        
  };
}

// 線程安全的函數(shù)緩存
public static Func<T, R> MemoizeThreadSafe<T, R>(Func<T, R> func) where T : IComparable
{
  ConcurrentDictionary<T, R> cache = new ConcurrentDictionary<T, R>();
  return arg => cache.GetOrAdd(arg, a => func(a));
}

// 利用延遲提高性能的函數(shù)緩存
public static Func<T, R> MemoizeLazyThreadSafe<T, R>(Func<T, R> func) where T : IComparable
{
  ConcurrentDictionary<T, Lazy<R>> cache = new ConcurrentDictionary<T, Lazy<R>>();
  return arg => cache.GetOrAdd(arg, a => new Lazy<R>(() => func(a))).Value;
}

上述示例代碼中有三個(gè)版本的函數(shù)記憶化。調(diào)用像下面這樣

public static string Greeting(string name)
{
  return $"Warm greetings {name}, the time is {DateTime.Now.ToString("hh:mm:ss")}";
}

public static void RunDemoMemoization()
{
  var greetingMemoize = Memoize<string, string>(Greeting);
  Console.WriteLine(greetingMemoize("Richard"));
  Console.WriteLine(greetingMemoize("Paul"));
  Console.WriteLine(greetingMemoize("Richard"));
}

線程安全字典ConcurrentDictionary可以保證只向集合里添加一個(gè)相同值,但函數(shù)求值可能會(huì)被執(zhí)行多次,所以利用.NET4之后的延遲對(duì)象加載技術(shù)。在真正需要使用對(duì)象時(shí)候才去實(shí)例化(通過訪問延遲對(duì)象的Value屬性),而且是線程安全的。

到此這篇關(guān)于.NET并發(fā)編程之函數(shù)閉包的文章就介紹到這了,更多相關(guān).NET函數(shù)閉包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談Asp.Net母版頁和內(nèi)容頁運(yùn)行機(jī)制

    淺談Asp.Net母版頁和內(nèi)容頁運(yùn)行機(jī)制

    這篇文章主要介紹了淺談Asp.Net母版頁和內(nèi)容頁運(yùn)行機(jī)制,詳細(xì)的介紹了母版頁和內(nèi)容頁的運(yùn)行過程步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-11-11
  • 頁面爬蟲(獲取其他頁面HTML)加載到自己頁面示例

    頁面爬蟲(獲取其他頁面HTML)加載到自己頁面示例

    利用頁面爬蟲(獲取其他頁面HTML)加載到自己頁面,實(shí)現(xiàn)所謂的小偷程序吧,具體實(shí)現(xiàn)代碼如下,感興趣的朋友可以參考下哈
    2013-06-06
  • asp.net基于session實(shí)現(xiàn)購(gòu)物車的方法

    asp.net基于session實(shí)現(xiàn)購(gòu)物車的方法

    這篇文章主要介紹了asp.net基于session實(shí)現(xiàn)購(gòu)物車的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了asp.net使用session存儲(chǔ)臨時(shí)數(shù)據(jù)實(shí)現(xiàn)購(gòu)物車功能的相關(guān)技巧,需要的朋友可以參考下
    2015-11-11
  • 詳解ASP.NET數(shù)據(jù)綁定操作中Repeater控件的用法

    詳解ASP.NET數(shù)據(jù)綁定操作中Repeater控件的用法

    .NET中的Repeater控件支持?jǐn)?shù)據(jù)模板,而且可以自由地定義樣式,這里我們就來詳解ASP.NET數(shù)據(jù)綁定操作中Repeater控件的用法,需要的朋友可以參考下
    2016-06-06
  • .NET 刷新頁面防止表單二次提交的實(shí)現(xiàn)方法

    .NET 刷新頁面防止表單二次提交的實(shí)現(xiàn)方法

    頁面上按鈕是服務(wù)器控件,現(xiàn)在刷新頁面要防止按鈕事件重復(fù)執(zhí)行。這篇文章給大家?guī)砹?net刷新頁面防止表單二次提交的實(shí)現(xiàn)方法,非常不錯(cuò),感興趣的朋友一起看看吧
    2016-09-09
  • ASP.NET防范SQL注入式攻擊的方法

    ASP.NET防范SQL注入式攻擊的方法

    所謂SQL注入式攻擊,就是攻擊者把SQL命令插入到Web表單的輸入域或頁面請(qǐng)求的查詢字符串,欺騙服務(wù)器執(zhí)行惡意的SQL命令,那么在ASP.NET中如何防范SQL注入式攻擊,下文為大家揭曉
    2016-05-05
  • ASP.NET操作Word的IIS權(quán)限設(shè)置

    ASP.NET操作Word的IIS權(quán)限設(shè)置

    檢索 COM 類工廠中 CLSID 為 {00024500-0000-0000-C000-000000000046} 的組件時(shí)失敗,原因是出現(xiàn)以下錯(cuò)誤: 80070005。
    2011-02-02
  • ASP.NET MVC Admin主頁快速構(gòu)建

    ASP.NET MVC Admin主頁快速構(gòu)建

    這篇文章主要為大家詳細(xì)介紹了ASP.NET MVC Admin主頁快速構(gòu)建的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • EF?Core通過顯式編譯提高查詢性能

    EF?Core通過顯式編譯提高查詢性能

    這篇文章介紹了EF?Core通過顯式編譯提高查詢性能的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • .NET中基于事件的異步模式-EAP

    .NET中基于事件的異步模式-EAP

    從.NET 4.5開始,支持的三種異步編程模式:基于事件的異步編程設(shè)計(jì)模式、異步編程模型、基于任務(wù)的編程模型,感興趣的朋友可以參考下
    2013-01-01

最新評(píng)論