理解c# 程式非同步async 跟await

隨著軟體開發的進步,以及硬體效能不斷增加,非同步程式設計是現代程式開發很重要的技術。在c# 主要以async 與await 二個關鍵字,讓非同步更直觀與容易管理。

非同步程式設計是允許程式在等待其他非阻塞任務操作完成時,能繼續執行其他任務的一個技術。能提高系統的回應性以及性能,尤其在處理高併發請求或者是耗時間的操作上。

async關鍵字

這個關鍵字主要用宣告這個方法是非同步的,但它不會去啟動一個新的執行緒,而是告訴compiler該下來的方法會有await的關鍵字,compiler需要為這個方法支持非同步的操作。

而async主要是宣告方法,而且只能回傳Task、Task<TResult>、void一起使用,但不建議void。

await關鍵字

awiat 是用來等待非同步操作完成用的關鍵字,只能在有宣告asyncASYNC的方法內部,compliler遇到await ,會將方法中其他部門註冊為等待任務延續,然後立既返回user。


using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
static async Task Main(string[] args) // Main也可以非同步的
{
try
{
string content = await DownloadContentAsync(“https://example.com”);
Console.WriteLine(content.Substring(0, 100));
}
catch (Exception ex)
{
Console.WriteLine($”An error occurred: {ex.Message}”);
}
}

static async Task DownloadContentAsync(string url)
{
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(url); // 透過非同步取得
response.EnsureSuccessStatusCode(); // 確定回應碼是是正確
return await response.Content.ReadAsStringAsync(); // 透過非同步取得回傳內容作回應
}
}
}

上面的例子中,透過await 關鍵字 donwloadcontentasync 的方法,不會阻塞主執行緒,而是允許程式在等網路回應時繼續執行其他任務

非同步的異常處理

在處理非同步的異常,可以用try catch 來await 。而非同步方法在拋出異常時,會封裝在回傳的Task 裡。

注意的事

避免在非同步用.Result 跟 wait() 會導致死結與效能問題

非同步方法會盡可能快速回傳,避免在非同步的方法裡執行需長時間運行的同步程式,會造成執行緖阻塞。
確實處理非同步中會發生的異常,避免程式崩潰與資料損毀

POS系統結合iPASS一卡通範例

12219570_10153067567121541_5370508928219483252_n
12208306_10153067535151541_1778219125832501158_n
一卡通(iPASS)是與悠遊卡(EasyCard)都是台灣的電子票證智慧卡,二者都是使用RFID(菲利浦的MIFARE)技術。今天來分享大致的技術~
首先,您得先到一卡通官方網站中的”加入特約商店“,提供相關資料向一卡通票證公司申請,並向一卡通公司申請測試機器及卡片。
審核通過後,iPASS一卡通公司會提供一台一卡通的測試機器,以及相關的文件及SDK。SDK與之前刷卡系統神似~
主要是輸入長度62的in.txt;輸出的out.txt則為109~928(有無交易記錄)。
1447167886093

POS系統介接與信用卡機連線的作法

Delphi或C#與信用卡連接的方式,有直接透過com port通訊或是透過呼叫exe的方式,利用in.txt、out.txt做溝通。然後回傳信用卡卡號/授權碼/刷卡金額等資訊。
示範一下Delphi與C#如何做信用卡線上刷卡。
Delphi

  public
    { Public declarations }
    ExecInfo : TShellExecuteInfo;   // use shellapi
    i:integer;
  end;
procedure TForm1.Button1Click(Sender: TObject);
var 
  s:String;
  ts:TStringlist;
begin
  ZeroMemory(@ExecInfo,SizeOf(ExecInfo));
  with ExecInfo do begin
    cbSize := SizeOf(ExecInfo);
    fMask := SEE_MASK_NOCLOSEPROCESS;
    lpVerb := 'open';
    lpFile := 'ecr.exe'; 
      Wnd := self.Handle;
    nShow := SW_HIDE; 
  end;
  s:='xxxxxxxxxxxxxxxxxxxx'; // 填上信用卡的溝通格式
  ts := Tstringlist.Create;
  ts.Clear;
  ts.Add(s);
  ts.SaveToFile('in.dat');
  ts.Free; 
  ShellExecuteEx(@ExecInfo);
  deletefile('out.dat');
  caption := '刷卡中...';
  timer1.Enabled := True;
  i:=0;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var ts1:Tstringlist;
sstatus,smoney,scard,sappno:String;
begin
  i:=i+1;
  if fileexists('out.dat') then begin
     Timer1.Enabled := false;
     ts1 := Tstringlist.Create;
     ts1.LoadFromFile('out.dat');
     if ts1.Count >0 then begin
       // 讀入檔案,解析格式
     end;
     ts1.Free;
  end;
end;
string dir = System.Windows.Forms.Application.StartupPath;
[DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        private void uForm1_Load(object sender, EventArgs e)
        {
            try
            {
                if (File.Exists(dir + "/out.txt")) //刪除out.txt
                    File.Delete(dir + "/out.txt");
                string code = "";  // in.txt格式
                using (StreamWriter sw = new StreamWriter(dir + "/in.txt"))   //小寫TXT     
                sw.Write(code);    
                IntPtr PDC = FindWindow(null, "ecr");  //開啟PosDataCom
                if (PDC == (IntPtr)0)
                {
                    try
                    {
                        Process p = new Process();
                        p.StartInfo.FileName = dir + "/ecrnccc.exe";
                        p.StartInfo.WorkingDirectory = dir;
                        p.StartInfo.UseShellExecute = false;
                        p.StartInfo.RedirectStandardInput = true;
                        p.StartInfo.RedirectStandardOutput = true;
                        p.StartInfo.RedirectStandardError = true;
                        p.StartInfo.CreateNoWindow = true;
                        p.Start();
                    }
                    catch (Exception exp)
                    {
                        return;
                    }
                }
               
               
                this.timer1.Enabled = true;
               
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (times == 5)
            {                
                times = 0;
                i++;
                if (i > 4)
                {
                    i = 0;
                    try
                {
                if (File.Exists(dir + "/out.txt"))
                {
                   
                    using (StreamReader sr = new StreamReader(dir + "/out.txt"))     //小寫TXT
                    {
                        String line;
                      
                        if ((line = sr.ReadLine()) != null)
                        {
                          // 解析
                        }
                        else
                            return false;
                        return true;
                    }
                }
                return false;
            }
            catch
            {
                return false;           
            }
                }
            }
            times++;
        }

讓佛祖、耶酥一起保佑程式碼無BUG,比乖乖有效?

微博上看到各國機房為了確保主機穩定不出怪事,請出法師、大師、神父到機房作法、禱告。

台灣最聞名的就是放乖乖了,然後要記得是綠燈(正常)的椰子乖乖:)

最近程式設計師流行直接寫在CODE裡,像上次寫的機器上除了要擺乖乖外,程式碼也該加上佛祖保佑,今天更出現耶穌版本。

[pascal]
// |~~~~~~~|
// | |
// | |
// | |
// | |
// | |
// |~.\\\_\~~~~~~~~~~~~~~xx~~~ ~~~~~~~~~~~~~~~~~~~~~/_//;~|
// | \ o \_ ,XXXXX), _..-~ o / |
// | ~~\ ~-. XXXXX`)))), _.–~~ .-~~~ |
// ~~~~~~~`\ ~\~~~XXX’ _/ ‘;)) |~~~~~~..-~ _.-~ ~~~~~~~
// `\ ~~–`_\~\, ;;;\)__.—.~~~ _.-~
// ~-. `:;;/;; \ _..-~~
// ~-._ `” /-~-~
// `\ / /
// | , | |
// | ‘ / |
// \/; |
// ;; |
// `; . |
// |~~~—–…..|
// | \ \
// | /\~~–…__ |
// (| `\ __-\|
// || \_ /~ |
// |) \~-‘ |
// | | \ ‘
// | | \ :
// \ | | |
// | ) ( )
// \ /; /\ |
// | |/ |
// | | |
// \ .’ ||
// | | | |
// ( | | |
// | \ \ |
// || o `.)|
// |`\\\\) |
// | |
// | |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// 耶穌保佑 永無 BUG
[/pascal]
同場加映
[pascal]
//
// _oo0oo_
// o8888888o
// 88" . "88
// (| -_- |)
// 0\ = /0
// ___/`—‘\___
// .’ \\| |// ‘.
// / \\||| : |||// \
// / _||||| -:- |||||- \
// | | \\\ – /// | |
// | \_| ”\—/” |_/ |
// \ .-\__ ‘-‘ ___/-. /
// ___’. .’ /–.–\ `. .’___
// ."" ‘< `.___\_<|>_/___.’ >’ "".
// | | : `- \`.;`\ _ /`;.`/ – ` : | |
// \ \ `_. \_ __\ /__ _/ .-` / /
// =====`-.____`.___ \_____/___.-`___.-‘=====
// `=—=’
//
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// 佛祖保佑 永無bug
//
//***************************************************
[/pascal]