IEA:再生能源對武漢肺炎適應力最佳 將是滿足2020需求增長的唯一能源

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

LG印度工廠化學氣體外洩已11死 村民抬遺體抗議要求關廠

摘錄自2020年5月10日自由時報報導

印度東南部維沙卡帕特南(Visakhapatnam)7日時,南韓LG集團子公司的聚合物工廠發生苯乙烯(styrene)氣體大規模外洩,據外媒,目前已知最少11死,逾千人住院,現仍有數百人在院內接受治療。當地時間週六,憤怒的村民將受害者遺體陳列於工廠大門前,要求工廠即刻關閉,同時逮捕工廠最高管理階層。

這間工廠屬於「南韓樂金聚合物(LG Polymers)」為南韓最大化工企業「LG化學(LG Chem Ltd)」的子公司。同日該公司發表聲明向受害者道歉,聲明也透露,初步調查結果證實,這場悲劇是由苯乙烯儲存槽蒸氣外洩而引起的。

苯乙烯被廣泛用於塑膠及橡膠製品製造,據我國勞動部職業安全衛生署2015「職業性苯乙烯、二苯乙烯中毒認定參考指引」,吸入或食入高濃度苯乙烯可能刺激呼吸道,引起昏睡、頭痛、精神混亂、協調感喪失及意識不清等症狀,若食入或在嘔吐下吸入肺部,可能導致嚴重肺組織損傷,引起肺組織壞死,甚至致死。

公害污染
空氣污染
毒物
污染治理
國際新聞
印度
化學工廠
化學氣體

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※推薦台中搬家公司優質服務,可到府估價

不只陸上生物會感染 科學家擔憂武漢肺炎恐可傳「鯨魚」

摘錄自2020年5月9日自由時報報導

武漢肺炎(新型冠狀病毒疾病,COVID-19)衝擊全球,不僅導致近400萬人染疫,與人類親近的犬、貓,甚至貂和大型貓科動物都有確診案例;專家則警告,雖目前還未有正式的科學期刊證實,但有研究顯示武漢肺炎可感染的潛在生物範圍恐擴及「鯨魚」。

根據加國媒體《Nunatsiaq news 》報導,目前科學界認為其他動物也會感染武漢肺炎的原因在於,牠們呼吸道細胞表面的蛋白質類似武漢肺炎的受體ACE2,當武漢肺炎病毒進入體內時,會經由ACE2進入細胞並開始複製,進而侵入呼吸道,造成感染。日前加利福尼亞大學戴維斯分校的研究人員創建了一份ACE2受體的動物清單,雖目前仍須更多研究佐證,但專家恩威亞(Martin Nweeia)日前在威爾遜國際學者中心的討論會上強調,北極海域的海洋哺乳動物有感染武漢肺炎的可能性。

雖然人類多透過飛沫感染到武漢肺炎,但根據國際文獻指出,人的糞便、尿液也會殘留病毒,當這些含有病毒的廢水排入水中時,有可能導致某些動物感染,雖然病毒可能被海水中的某些物質破壞,但是北極海有多個鹹淡水入口,以及因全球暖化冰川徑流和夏季冰融化增加了淡水系統,可能影響海洋生物以及病毒的存活。

生活環境
生態保育
物種保育
生物多樣性
國際新聞
武漢肺炎
鯨魚
動物與大環境變遷
公共衛生

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

網頁設計最專業,超強功能平台可客製化

疫情衝擊酪農 日本北海道知事推牛奶挑戰

摘錄自2020年5月10日中央通訊社報導

日本境內2019冠狀病毒疾病(COVID-19)疫情延燒,連帶衝擊到北海道酪農生乳銷量,讓北海道知事鈴木直道推出「牛奶挑戰」,呼籲民眾多喝牛奶,增加牛奶或優格購買量。日本放送協會(NHK)報導,鈴木直道在一段影片中單手拿著一杯牛奶,然後一口氣喝完,這個稱為「牛奶挑戰」的活動,希望能提升牛奶消費量。

日本境內受到疫情影響,學校臨時停課,所以沒有提供營養午餐,讓牛奶消費量下滑;民眾避免外出及出遊,也造成牛奶製品的冰淇淋、蛋糕等甜點銷量銳減。牛奶消費量減少直接衝擊酪農,而北海道的農業生產額中,酪農占了4成,在北海道農產占有相當重要地位。

一般來說,需求減少可以減產因應,但事實上不然,北海道江別市酪農川口谷仁說,每天要幫牛擠3次奶,如果不這麼做,牛就會生病,所以無法停止擠奶。加上北海道每年5月到6月的氣候,對牛來說是最舒服的時候,也是一年中最容易增加生乳產量的時期。而再這樣下去的話,最糟的情況就是造成廠商無法再收購,每天固定生產的生乳將不得不廢棄。

生活環境
國際新聞
日本
北海道
酪農
牛奶
武漢肺炎
疫情下的食衣住行
公共衛生
經濟動物
動物福利

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計最專業,超強功能平台可客製化

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家公司費用怎麼算?

給非目標魚類的「逃生指示燈」 研究:漁網裝LED燈 可使混獲減半

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

疫情讓自然資源復甦 泰國家公園擬每年關3個月

摘錄自2020年5月11日中央社報導

為了避免武漢肺炎疫情擴大,泰國從3月25日關閉所有的國家公園,例如知名的考艾國家公園(Khao Yai National Park)是開園58年以來第一次閉園,而且數條穿過國家公園的公路也因此封閉。

泰國公視(Thai PBS)報導,泰國自然資源和環境部(Ministry of Natural Resources and Environment)部長烏拉沃(Varawut Silpa-archa)日前表示,過去兩個月國家公園因為疫情閉園,反讓許多野生動物再生。

烏拉沃表示,受到這樣狀況的啟發,自然資源和環境部未來準備讓全泰國157個國家公園每年閉園三個月,他要求國家公園局(Department of National Parks, Wildlife and Plant Conservation)在一切恢復正常後,研擬適合的閉園時間表。

泰媒經理人日報(Manager Daily)報導,國家公園局局長譚亞(Thanya Netithamkul)表示,國家公園局已經和相關單位討論過,會要求各個國家公園準備相關計畫。

生態保育
生物多樣性
國際新聞
泰國
國家公園
疫情

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※回頭車貨運收費標準

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

基於Azure IoT開發.NET物聯網應用系列-全新的Azure IoT架構

物聯網技術已經火了很多年了,業界各大廠商都有各自成熟的解決方案。我們公司主要搞新能源汽車充電,充電樁就是物聯網技術的最大應用,車聯網、物聯網、互聯網三網合一。2017年的時候重點研究過Azure IoT技術架構和使用,

Azure IoT 技術研究系列1-入門篇

隨着業界技術的發展,近期又重新關注並研究了最新的Azure  IoT架構,現在將結合著.NET Core技術和Azure IoT 做一些物聯網應用,將研究的成果分享給大家。

關於IoT的一些基本概念,重新梳理一下,分享給大家:

  • IoT:Internet of Things,即萬物互聯。
  • IoT Devices:物聯網設備。
  • IoT Edge Devices:物聯網邊緣計算設備。
  • IoT Gateway:IoT網關,負責IoT物聯網設備的接入、管理和控制、通訊(上行和下行)
  • 通訊協議:TCP、MQTT、AMQP、HTTPS、zgebee等等
  • Azure IoT Central。 IoT Central 是完全託管的 IoT物聯網 SaaS(軟件即服務)服務
  • 目前Azure仍然提供了Azure IoT Hub:直譯為Azure的物聯網中心
  • Azure IoT Hub為物聯網設備提供註冊、管理、溝通交互的雲服務。可用於管理數十億物聯網設備,提供可靠和安全的雲端與設備之間的雙向通信支持,每月可處理數以萬億計消息,並簡化了與其他Azure服務之間的集成,包括Azure機器學習以及
  • Azure流分析等。它是微軟Azure IoT Suite的重要組成部分,也是微軟物聯網戰略的重要基礎。

接下來,我們看一下Azure IoT最新的技術架構:

   

   下面,我們詳細介紹一下這個架構組成:

   一、 Things(物聯網設備側)

  1. IoT devices:前面已經介紹過了,泛指各類物聯網設備。設備可以安全地註冊到雲中,並且可以連接到雲之後,發送和接收數據。

  2. IoT edge devices:物聯網邊緣計算設備,某些設備可能會是在設備本身上或在現場網關中執行一些數據處理的邊緣設備。舉個大家平時常見的設備:充電樁,作為IoT邊緣計算設備,其自身有嵌入式操作系統、AI智能芯片,可以實現一些簡單的邊緣計算場景

  3. Cloud Gateway:雲網關,雲網關提供一個雲中心,以便設備安全地連接到雲併發送數據。 它還提供設備管理功能,包括設備的命令和控制。

      對於雲網關,Azure 建議使用Azure  IoT 中心。Azure IoT 中心是從設備引入事件的託管雲服務,充當設備與後端服務之間的消息代理。 同時提供安全連接、事件引入、雙向通信和設備管理。

      當然,我們也可以自建雲網關,支持各類物聯網設備的接入、管理和控制。

  4. Bulk devices provisioning:設備批量設置,統一管理設置海量設備。 對於註冊和連接許多組設備。可以使用 IoT 中心設備預配服務 (DPS)。 DPS 可用於大規模分配設備並將設備註冊到特定 Azure IoT 中心終結點。

二、Insights(洞察、洞見,可以理解為設備接入管理、數據處理、數據持久化、數據分析、可視化)

  1. Streaming Processing:流式數據處理

  Azure提供了專門的流分析服務。 流分析可以使用時間開窗函數、流聚合和外部數據源聯接大規模執行複雜分析。假如說我們自建系統做物聯網數據流式分析的話,可以使用Kafka、Flink、Spark等主流的大數據流式分析技術。

  2. Data transformation:數據轉換操作或聚合遙測數據流。

  常見的場景包括通訊協議轉換,例如,將二進制數據轉換為 JSON,或者合併數據點。 如果數據在到達 IoT 中心之前必須轉換,可以使用協議網關(一個可以轉換數據的網關)。 同時,數據可以在到達 IoT 中心後轉換。

  在這種情況下,可以使用 Azure Functions 函數計算,Azure Functions內置了與 IoT 中心、Cosmos DB 和 Blob 存儲的集成。

  3. Warm path store:熱存儲

  熱存儲,存儲實時物聯網設備上傳下發的數據,這些數據必須可按設備實時查詢,以用於報告和可視化。舉個實際的業務場景:充電樁實時上傳的電壓、電流、SOC等實時設備數據,這些數據的實時性要求高,可以存儲在熱存儲中。

  4. Cold path store:冷存儲

  如果所有的物聯網設備數據全部存儲在熱存儲中,其硬件成本會很高。數據具備一定的時效性,因為,當數據失去了一定的時效性要求后,可以存儲在冷存儲中,降低存儲的成本。

  這些數據會保留較長時間,用於批處理。 對於冷路徑存儲,可以使用 Azure Blob 存儲。 數據可無限期地以較低成本在 Blob 存儲中存檔,並且可以輕鬆訪問以進行批處理。

  5. UI Reporting and tools:可視化展現

  可視化展現方面,通常包含:IoT設備管理UI、設備控制UI、趨勢圖、連接狀態圖表、數據分析圖表等等,這個地方可以使用各類UI展現技術實現了。

三、 Action(運維管理、操作)

  1. Machine Learning:機器學習

   大家會問,用機器學習干什麼?通過歷史遙測數據執行模型訓練,實現IoT設備的預測性維護,同時還能做什麼?還可以對上報的數據建立不同的模型,實時進行訓練,智能控制設備。比如說充電樁的例子,動態調控充電功率,實現最大充電效率。

  2. Business integration:業務流程集成

   業務流程集成根據來自設備數據執行各類後續操作。 可以包括:存儲實時消息、引發警報、發送电子郵件或短信,或者與 CRM 集成。舉個實際的業務場景:當需要設備運維時,發出一個運維工單到產品運維部門,實現IoT設備的智能運維和派單處理。

  3. User Management:用戶管理

   用戶管理限制哪些用戶或組可以在設備上執行操作,例如升級固件。 它還定義應用程序中的用戶功能。

  綜上是Azure IoT架構的詳細介紹和說明,比2017年時,產品更加SaaS化,更加AI智能、更加體系。分享給大家。

 

 

周國慶

2020/6/7

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

異步函數async await在wpf都做了什麼?

首先我們來看一段控制台應用代碼:

 class Program
 {
     static async Task Main(string[] args)
     {
        System.Console.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}");
        var result = await ExampleTask(2);
        System.Console.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}");
        System.Console.WriteLine(result);
        Console.WriteLine("Async Completed");
     }

     private static async Task<string> ExampleTask(int Second)
     {
        await Task.Delay(TimeSpan.FromSeconds(Second));
        return $"It's Async Completed in {Second} seconds";
     }
 }

輸出結果

Thread Id is Thread:1,Is Thread Pool:False
Thread Id is Thread:4,Is Thread Pool:True
It's Async Completed in 2 seconds
Async Completed

如果這段代碼在WPF運行,猜猜會輸出啥?

      private async void Async_Click(object sender, RoutedEventArgs e)
      {
          Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}");
          var result= await ExampleTask(2);
          Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}");
          Debug.WriteLine(result);
          Debug.WriteLine("Async Completed");   
      }

      private async Task<string> ExampleTask(int Second)
      {
          await Task.Delay(TimeSpan.FromSeconds(Second));
          return $"It's Async Completed in {Second} seconds";
      }

輸出結果:

Thread Id is Thread:1,Is Thread Pool:False
Thread Id is Thread:1,Is Thread Pool:False
It's Async Completed in 2 seconds
Async Completed

這時候你肯定是想說,小朋友,你是否有很多問號????,我們接下看下去

一.SynchronizationContext(同步上下文)

首先我們知道async await 異步函數本質是狀態機,我們通過反編譯工具dnspy,看看反編譯的兩段代碼是否有不同之處:

控制台應用:

internal class Program
{
    [DebuggerStepThrough]
	private static Task Main(string[] args)
	{
		Program.<Main>d__0 <Main>d__ = new Program.<Main>d__0();
		<Main>d__.args = args;
		<Main>d__.<>t__builder = AsyncTaskMethodBuilder.Create();
		<Main>d__.<>1__state = -1;
		<Main>d__.<>t__builder.Start<Program.<Main>d__0>(ref <Main>d__);
		return <Main>d__.<>t__builder.Task;
	}
    
	[DebuggerStepThrough]
	private static Task<string> ExampleTask(int Second)
	{
		Program.<ExampleTask>d__1 <ExampleTask>d__ = new Program.<ExampleTask>d__1();
		<ExampleTask>d__.Second = Second;
		<ExampleTask>d__.<>t__builder = AsyncTaskMethodBuilder<string>.Create();
		<ExampleTask>d__.<>1__state = -1;
		<ExampleTask>d__.<>t__builder.Start<Program.<ExampleTask>d__1>(ref <ExampleTask>d__);
		return <ExampleTask>d__.<>t__builder.Task;
	}

	[DebuggerStepThrough]
	private static void <Main>(string[] args)
	{
	        Program.Main(args).GetAwaiter().GetResult();
	}
}

WPF:

public class MainWindow : Window, IComponentConnector
{

	public MainWindow()
	{
	       this.InitializeComponent();
	}

	[DebuggerStepThrough]
	private void Async_Click(object sender, RoutedEventArgs e)
	{
		MainWindow.<Async_Click>d__1 <Async_Click>d__ = new MainWindow.<Async_Click>d__1();
		<Async_Click>d__.<>4__this = this;
		<Async_Click>d__.sender = sender;
		<Async_Click>d__.e = e;
		<Async_Click>d__.<>t__builder = AsyncVoidMethodBuilder.Create();
		<Async_Click>d__.<>1__state = -1;
		<Async_Click>d__.<>t__builder.Start<MainWindow.<Async_Click>d__1>(ref <Async_Click>d__);
	}

	[DebuggerStepThrough]
	private Task<string> ExampleTask(int Second)
	{
	        MainWindow.<ExampleTask>d__3 <ExampleTask>d__ = new MainWindow.<ExampleTask>d__3();
		<ExampleTask>d__.<>4__this = this;
		<ExampleTask>d__.Second = Second;
		<ExampleTask>d__.<>t__builder = AsyncTaskMethodBuilder<string>.Create();
		<ExampleTask>d__.<>1__state = -1;
		<ExampleTask>d__.<>t__builder.Start<MainWindow.<ExampleTask>d__3>(ref <ExampleTask>d__);
		return <ExampleTask>d__.<>t__builder.Task;
	}

	[DebuggerNonUserCode]
	[GeneratedCode("PresentationBuildTasks", "4.8.1.0")]
	public void InitializeComponent()
	{
		bool contentLoaded = this._contentLoaded;
		if (!contentLoaded)
		{
		     this._contentLoaded = true;
		     Uri resourceLocater = new Uri("/WpfApp1;component/mainwindow.xaml", UriKind.Relative);
		     Application.LoadComponent(this, resourceLocater);
		}
	}
	private bool _contentLoaded;
}

我們可以看到完全是一致的,沒有任何區別,為什麼編譯器生成的代碼是一致的,卻會產生不一樣的結果,我們看看創建和啟動狀態機代碼部分的實現:

public static AsyncVoidMethodBuilder Create()
{
	SynchronizationContext synchronizationContext = SynchronizationContext.Current;
	if (synchronizationContext != null)
	{
		synchronizationContext.OperationStarted();
	}
	return new AsyncVoidMethodBuilder
	{
		_synchronizationContext = synchronizationContext
	};
}

[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Start<[Nullable(0)] TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
	AsyncMethodBuilderCore.Start<TStateMachine>(ref stateMachine);
}

[DebuggerStepThrough]
public static void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
	if (stateMachine == null)
	{
		ThrowHelper.ThrowArgumentNullException(ExceptionArgument.stateMachine);
	}
	Thread currentThread = Thread.CurrentThread;
	Thread thread = currentThread;
	ExecutionContext executionContext = currentThread._executionContext;
	ExecutionContext executionContext2 = executionContext;
	SynchronizationContext synchronizationContext = currentThread._synchronizationContext;
	try
	{
	     stateMachine.MoveNext();//狀態機執行代碼
	}
	finally
	{
	     SynchronizationContext synchronizationContext2 = synchronizationContext;
	     Thread thread2 = thread;
	     if (synchronizationContext2 != thread2._synchronizationContext)
	     {
		  thread2._synchronizationContext = synchronizationContext2;
	     }
	     ExecutionContext executionContext3 = executionContext2;
	     ExecutionContext executionContext4 = thread2._executionContext;
	     if (executionContext3 != executionContext4)
	     {
		 ExecutionContext.RestoreChangedContextToThread(thread2, executionContext3, executionContext4);
	     }
	}
}

在這裏總結下:

  • 創建狀態機的Create函數通過SynchronizationContext.Current獲取到當前同步執行上下文
  • 啟動狀態機的Start函數之後通過MoveNext函數執行我們的異步方法
  • 這裏還有一個小提示,不管async函數裏面有沒有await,都會生成狀態機,只是MoveNext函數執行同步方法,因此沒await的情況下避免將函數標記為async,會損耗性能

同樣的這裏貌似沒能獲取到原因,但是有個很關鍵的地方,就是Create函數為啥要獲取當前同步執行上下文,之後我從MSDN找到關於SynchronizationContext
的介紹,有興趣的朋友可以去閱讀以下,以下是各個.NET框架使用的SynchronizationContext:

SynchronizationContext 默認
WindowsFormsSynchronizationContext WindowsForm
DispatcherSynchronizationContext WPF/Silverlight
AspNetSynchronizationContext ASP.NET

我們貌似已經一步步接近真相了,接下來我們來看看DispatcherSynchronizationContext

二.DispatcherSynchronizationContext

首先來看看DispatcherSynchronizationContext類的比較關鍵的幾個函數實現:

public DispatcherSynchronizationContext(Dispatcher dispatcher, DispatcherPriority priority)
{
     if (dispatcher == null)
     {
         throw new ArgumentNullException("dispatcher");
     }
     Dispatcher.ValidatePriority(priority, "priority");
     _dispatcher = dispatcher;
     _priority = priority;
     SetWaitNotificationRequired();
 }

//同步執行
public override void Send(SendOrPostCallback d, object state)
{
     if (BaseCompatibilityPreferences.GetInlineDispatcherSynchronizationContextSend() && _dispatcher.CheckAccess())
     {
         _dispatcher.Invoke(DispatcherPriority.Send, d, state);
     }
     else
     {
          _dispatcher.Invoke(_priority, d, state);
     }
}

//異步執行
public override void Post(SendOrPostCallback d, object state)
{
     _dispatcher.BeginInvoke(_priority, d, state);
}

我們貌似看到了熟悉的東西了,Send函數調用Dispatcher的Invoke函數,Post函數調用Dispatcher的BeginInvoke函數,那麼是否WPF執行異步函數之後會調用這裏的函數嗎?我用dnspy進行了調試:

我通過調試之後發現,當等待執行完整個狀態機的之後,也就是兩秒后跳轉到該Post函數,那麼,我們可以將之前的WPF那段代碼大概可以改寫成如此:

private async void Async_Click(object sender, RoutedEventArgs e)
{
    //async生成狀態機的Create函數。獲取到UI主線程的同步執行上下文
    DispatcherSynchronizationContext synchronizationContext = (DispatcherSynchronizationContext)SynchronizationContext.Current;
    
    //UI主線程執行
    Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}");
    
    //開始在狀態機的MoveNext執行該異步操作
    var result= await ExampleTask(2);
    
    //等待兩秒,異步執行完成,再在同步上下文異步執行
    synchronizationContext.Post((state) =>
    {
         //模仿_dispatcher.BeginInvoke
         Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}");
         Debug.WriteLine(result);
         Debug.WriteLine("Async Completed");  
     },"Post");           
 }

輸出結果:

Thread Id is Thread:1,Is Thread Pool:False
Thread Id is Thread:1,Is Thread Pool:False
It's Async Completed in 2 seconds
Async Completed

也就是asyn負責生成狀態機和執行狀態機,await將代碼分為兩部分,一部分是異步執行狀態機部分,一部分是異步執行完之後,通過之前拿到的DispatcherSynchronizationContext,再去異步執行接下來的部分。我們可以通過dnspy調試DispatcherSynchronizationContext的 _dispatcher字段的Thread屬性,知道Thread為UI主線程,而同步界面UI控件的時候,也就是通過Dispatcher的BeginInvoke函數去執行同步的

三.Task.ConfigureAwait

Task有個ConfigureAwait方法,是可以設置是否對Task的awaiter的延續任務執行原始上下文,也就是為true時,是以一開始那個UI主線程的DispatcherSynchronizationContext執行Post方法,而為false,則以await那個Task裏面的DispatcherSynchronizationContext執行Post方法,我們來驗證下:

我們將代碼改為以下:

private async void Async_Click(object sender, RoutedEventArgs e)
{
    Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}");
    var result= await ExampleTask(2).ConfigureAwait(false);
    Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}");
    Debug.WriteLine(result);
    Debug.WriteLine($"Async Completed");
}

輸出:

Thread Id is Thread:1,Is Thread Pool:False
Thread Id is Thread:4,Is Thread Pool:True
It's Async Completed in 2 seconds
Async Completed

結果和控制台輸出的一模一樣,且通過dnspy斷點調試依舊進入到DispatcherSynchronizationContext的Post方法,因此我們也可以證明我們上面的猜想,而且默認ConfigureAwait的參數是為true的,我們還可以將異步結果賦值給UI界面的Text block:

private async void Async_Click(object sender, RoutedEventArgs e)
{
    Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}");
    var result= await ExampleTask(2).ConfigureAwait(false);
    Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}");
    this.txt.Text = result;//修改部分
    Debug.WriteLine($"Async Completed");
}

拋出異常:

調用線程無法訪問此對象,因為另一個線程擁有該對象

補充
推薦林大佬的一篇文章,也講的也簡潔透徹C# dotnet 自己實現一個線程同步上下文

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

※回頭車貨運收費標準

ASP.NET Core通過Nacos SDK讀取阿里雲ACM

背景

前段時間,cranelee 在Github上給老黃提了個issues, 問到了如何用Nacos的SDK訪問阿里雲ACM。

https://github.com/catcherwong/nacos-sdk-csharp/issues/13

剛看到這個issues的時候,老黃也是覺得一臉懵逼,好像這兩者沒有什麼必然聯繫,打開ACM的文檔一看,就知道為什麼了。

原來Java和Go的已經是可以用nacos的SDK來訪問的了。那就說明兩者是兼容的。

這段時間抽空看了一下,把這個功能基本實現了。

下面就簡單介紹一下。

簡單看看ACM

開通ACM之後,可以看到類似這樣的界面。其實和Nacos控制台的配置部分差不遠。

要使用這個的話,需要幾個東西,一個是ACM上面的命名空間,一個是AccessKey ID,一個是AccessKey Secret。

其中的AK/SK可以在命名空間詳情裏面獲取。

然後就是添加配置了。

三張圖,看個大概就好了,下面來具體看看在.NET Core中怎麼使用。

如何使用

安裝最新預覽版的SDK

<ItemGroup>
    <PackageReference Include="nacos-sdk-csharp-unofficial.Extensions.Configuration" Version="0.2.7-alpha7" />
</ItemGroup>

注:目前還沒有發布正式版,不過不影響正常使用了。

修改Program

public class Program
{
    public static void Main(string[] args)
    {
        // 處理編碼問題
        System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, builder) =>
            {
                // 這兩行代碼就是關鍵
                var c = builder.Build();
                builder.AddNacosConfiguration(c.GetSection("NacosConfig"));
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

調整appsettings.json

{
  "NacosConfig": {
    "Optional": false,
    "DataId": "msconfigapp",
    "Group": "",
    "Tenant": "<換成您的命名空間>",
    "ServerAddresses": [],
    "AccessKey": "<換成您的AK>",
    "SecretKey": "<換成您的SK>",
    "EndPoint": "acm.aliyun.com"
  }
}

注: 由於老黃開通個人開通的,沒有內網服務器,所以用的是公網的EndPoint,這個需要根據情況自行調整。

實體映射(非必須)

public class AppSettings
{
    public string Str { get; set; }

    public int Num { get; set; }

    public List<int> Arr { get; set; }

    public SubObj SubObj { get; set; }
}

public class SubObj
{
    public string a { get; set; }
}

為了方便和配置一一對應,可以建立實體,做一個映射。

加了這個的,需要在Startup上面配置一下。

public void ConfigureServices(IServiceCollection services)
{   
    // others ...
    
    services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
}

讀取配置

這裏用控制器做為示例

[ApiController]
[Route("api/[controller]")]
public class ConfigController : ControllerBase
{
    private readonly ILogger<ConfigController> _logger;
    private readonly IConfiguration _configuration;
    private readonly AppSettings _settings;
    private readonly AppSettings _sSettings;
    private readonly AppSettings _mSettings;

    public ConfigController(
        ILogger<ConfigController> logger,
        IConfiguration configuration,
        IOptions<AppSettings> options,
        IOptionsSnapshot<AppSettings> sOptions,
        IOptionsMonitor<AppSettings> _mOptions
        )
    {
        _logger = logger;
        _configuration = configuration;
        _settings = options.Value;
        _sSettings = sOptions.Value;
        _mSettings = _mOptions.CurrentValue;
    }

    [HttpGet]
    public string Get()
    {
        string id = Guid.NewGuid().ToString("N");

        _logger.LogInformation($"============== begin {id} =====================");

        var conn = _configuration.GetConnectionString("Default");
        _logger.LogInformation($"{id} conn = {conn}");

        var version = _configuration["version"];
        _logger.LogInformation($"{id} version = {version}");

        var str1 = Newtonsoft.Json.JsonConvert.SerializeObject(_settings);
        _logger.LogInformation($"{id} IOptions = {str1}");

        var str2 = Newtonsoft.Json.JsonConvert.SerializeObject(_sSettings);
        _logger.LogInformation($"{id} IOptionsSnapshot = {str2}");

        var str3 = Newtonsoft.Json.JsonConvert.SerializeObject(_mSettings);
        _logger.LogInformation($"{id} IOptionsMonitor = {str3}");

        _logger.LogInformation($"===============================================");
        _logger.LogInformation($"===============================================");
        _logger.LogInformation($"===============================================");

        return "ok";
    }
}

附上一張操作動圖

在ACM上修改之後,程序是可以馬上讀取到的。

下面是本文的示例代碼。

https://github.com/catcherwong-archive/2020/tree/master/06/NacosACMDemo

小結

Nacos和ACM的操作基本都是一致的,比較不一樣的地方是,從直連Nacos變成要先去地址服務拿到Nacos的地址后再操作。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

※回頭車貨運收費標準

[C#.NET 拾遺補漏]03:你可能不知道的幾種對象初始化方式

閱讀本文大概需要 1.2 分鐘。

隨着 C# 的升級,C# 在語法上對對象的初始化做了不少簡化,來看看有沒有你不知道的。

數組的初始化

在上一篇羅列數組的小知識的時候,其中也提到了數組的初始化,這時直接引用過來。

int[] arr = new int[3] {1, 2, 3}; // 正兒八經的初始化
int[] arr = new [] {1, 2, 3}; // 簡化掉了 int 和數組容量聲明
int[] arr = {1, 2, 3}; // 終極簡化

字典的兩種初始化方式

第二種是 C# 6 的語法,可能很多人不知道。

// 方式一:
var dict = new Dictionary<string, int>
{
{ "key1", 1 },
{ "key2", 20 }
};

// 方式二:
var dict = new Dictionary<string, int>
{
["key1"] = 1,
["key2"] = 20
};

含自定義索引器的對象初始化

這種初始化原理上其實是和上面字典的第二種初始化是一樣的。

public class IndexableClass
{
public int this[int index]
{
set
{
Console.WriteLine("{0} was assigned to index {1}", value, index);
}
}
}

var foo = new IndexableClass
{
[0] = 10,
[1] = 20
}

元組(Tuple)的三種初始化方式

前面兩種方式很常見,後面一種是 C# 7 的語法,可能有些人不知道。

// 方式一:
var tuple = new Tuple<string, int, MyClass>("foo", 123, new MyClass());

// 方式二:
var tuple = Tuple.Create("foo", 123, new MyClass());

// 方式三:
var tuple = ("foo", 123, new MyClass());

另外補充個小知識,在 C# 7 中,元組的元素可以被解構命名:

(int number, bool flage) tuple = (123, true);
Console.WriteLine(tuple.number); // 123
Console.WriteLine(tuple.flag); // True

自定義集合類的初始化

只要自定義集合類包含Add方法,便可以使用下面這種初始化方式為集合初始化元素。

class Program
{
static void Main()
{
var collection = new MyCollection {
"foo", // 對應方法:Add(string item)
{ "bar", 3 }, // 對應方法:Add(string item, int count)
"baz", // 對應方法:Add(string item)
123.45d, // 對應擴展方法:Add(this MyCollection @this, double value)
};
}
}

class MyCollection : IEnumerable
{
privatereadonly IList _list = new ArrayList();

public void Add(string item)
{
_list.Add(item);
}

public void Add(string item, int count)
{
for (int i = 0; i < count; i++)
{
_list.Add(item);
}
}

public IEnumerator GetEnumerator()
{
return _list.GetEnumerator();
}
}

static class MyCollectionExtensions
{
public static void Add(this MyCollection @this, double value) =>
@this.Add(value.ToString());
}

對象的集合屬性初始化

我們知道對集合的初始化必須使用new創建該集合,不能省略,比如:

// OK
IList<string> synonyms = new List<string> { "c#", "c-sharp" };

// 編譯報錯,不能省略 new List<string>
IList<string> synonyms = { "c#", "c-sharp" };

但如果該集合作為另外一個類的屬性,則可以省略new,比如:

public class Tag
{
public IList<string> Synonyms { get; set; } = new List<string>();
}

var tag = new Tag
{
Synonyms = { "c#", "c-sharp" } // OK
};

能想到和找到的就這麼點了,希望以上會對你的編程有所幫助。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

台中搬家公司費用怎麼算?