[Webアプリ]WebSocketとGoogleMapsでリアルタイム監視マップを作る。その1。

結構簡単に出来る。
全国に複数ある工場の異常をリアルタイムに監視できるマップをWebSocketとGoogleMapsを使って作ってみたいと思います。

やりたいこと。
・全国の拠点(工場や事務所)で発生したイベント(警報、警告など)をWebSocketとGoogleMapsを使ってリアルタイム監視したい。

イメージ
Img20130315001252

実行画面

JSONとWebSocketのおかげ。
動作の仕組みとしてはモニター対象の各クライアントが送信したJSON文字列をサーバーが接続中のWebSocketクライアントにブロードキャストしています。
WebSocketなので、サーバーはモニター対象のクライアントをポーリングする必要はなく、クライアントはイベントが発生したタイミングでサーバーに情報を送信することができます。また、ブラウザもWebSocketセッションを張りっぱなしなので、ブラウザリロードなどの必要はありません。まぁ、セッションが切れないという保証はないと思いますので、その辺の考慮は必要ですが。。。

GoogleMapsAPIの使用方法については、下記のサイト様を参考にしました。このサイト作った人ほんとすごいですよねー。

ドットインストール – Google Maps API入門
http://dotinstall.com/lessons/basic_google_maps

[雑記]イマドキJCのパソコン事情。

親戚のJCがパソコン欲しいっていうから一緒に買いに行ってきた。
親戚のJC(女子中学生)がパソコンが欲しいというので、僕がパソコンに詳しいということで、一緒に買いに行ってきた。まぁ、おじさん(お父さん)と3人だったのだけれどー。
いやぁ、JCと話す機会なんて無いから、ちょっと気構えたけれど^^;

ノートパソコンが安い。
某ヤマダ電機にパソコンを買いに。今はWindows8のパソコンしかなく、普及価格帯は10万円前後。予算は13万というので、プリンタ込でも十分だったし、いやー、安くなったもんだ。今のPCの値段の違いは、CPUのモデルとブルーレイが付くかどうかがポイントになる気がする。あとは発売時期による値段の差か。
よくパソコンは何を買うのがいい?と聞かれるですが、僕はいつも好きなものを買ったらいいって言っているので、そう言ったけど親戚のJCはどのパソコンにするかはあまり興味がなさそうで、、、結局、富士通のCorei5のブルーレイありモデルを買った。メモリも8GBだったし、10%のポイントがついて9万円台は安いと思った。

1時間以上はかかるインターネットの手続き。
親戚のうちはネットなしだったので、パソコンの購入とフレッツ光の手続きへ。たまたま某YahooBBの販売員に全自動的に勧められ、他のプロバイダと比較することもなく手続きへ。
パソコンと同時にフレッツ光の手続きをすることで、開通後3万円ほどキャッシュバックがあるのだが、これは店側に入るインセンティブにより可能なこと。昔は回線に入るだけで良かったけど、今のインターネットは付加価値サービスが無数に存在し、それらの申し込みが前提となっている、っぽい。特に某Yahooなんて一昔前は申し込みしなくてもモデムが送られてくっていうので悪名高かったし。携帯キャリアと老舗ポータルサイトという強みを生かし、全方位的なサービス(セキュリティサービスから家事手伝いまで)の加入が前提であった。1つのオプションにつき、500円程度なのだけれど、それが10個くらいあって、2ヶ月は無料なのだけれど、その後は課金される仕組み。解約を忘れるとえらい金額が請求されるので注意が必要。

さて、そんなこんなで、手続きに1時間くらいかかった。一人の客に10数万の買い物で、1時間以上ってかかりすぎー。まぁ、携帯買う時もそうですけどね。今はインターネットをしていない家庭のほうが珍しいから、1日数件程度の加入件数なのでしょう、地方都市の場合は。だから時間を掛けられるわけです。説明もちゃんとしろって言われてるんだろうなぁ。

量販店はどうやって儲けるのか。
さて、Windows8はストアからのソフトのインストールにMicrosoftのアカウントが必要だったり、OSのアクティベーションはもちろんのこと、ネットが繋がらないと面倒なことが多いです。だからパソコンを買った最後に、いろいろ面倒くさいから設定やりますよ的な話をされました。まぁ、ある程度の親切心的なところも今はあるのだろうけど。全部断りましたが(^_^;)
でも店側はそうやって儲けるしか無いわけで、実際にやり方を知っていると、ソフトのインストールに数千円だったり高すぎワロタになるのですが、初心者からするとそういったサービスも必要なのかも。パソコンが安すぎてソフト的な面で稼がないとお店としては利益がないわけですね。だって、店内は客より販売員の方が多いのだから~。

JCのパソコン事情。
イマドキ、パソコンが無い家庭は珍しい訳で、親戚のJCは欲しい欲しい言っていたのですが、どうもゲーム機をネットに繋ぎたかったらしい。まぁ、そうだよなぁと。音楽を取り込んでPSPに入れたいとか、DS繋ぎたいとか・・・。まぁ、そうだよなぁ、それがしたいんだよね。親御さんは勉強、勉強というわけですよ。ちなみに、中学1年生なのでパソコンの授業はパワーポイントで写真を貼って発表するくらい。もっと英語の授業とか難しくなるとネットで翻訳できちゃったりするんですけどね。周りの友達はブログをやっているって子がいるくらい。呟いたり、イイネイイネしている子はまだいなさそう。そんなもんかー。

恐いインターネットから子供を守るには。
さて、インターネットが繋がらないパソコンなんてただの箱、といってもいいくらい今はインターネットに依存していますが、インターネットの世界は非常に恐いものです。クラウドクラウド言っていますが、Googleなんて1度データを保存すると3箇所のデータセンターのサーバーにバックアップし万全な冗長性を誇っています。すなわち、ネットに個人情報が流出したら、いろいろなところに情報がコピーされ、その情報がどう利用されるかは分からない世界です。
こんな恐ろしい世界であることは子供たちはわからないし、興味心からチョメチョメなことを検索してしまうことは安易に考えられます。これは、学校である程度は教えると思うのですが、一番は親が管理することです。僕はよくパソコンの相談されるのですが、子供が居る家庭では必ずそのことを話します。まぁ、実体験もあるし笑。僕がー、◯学生の時はー、当時、ダイヤルアップで接続して、チョメチョメサイトを良く検索したものです。でも、その時代と比べ物にならないくらい、いろいろな情報がインターネットにはあふれています。そういった危険性があることは親が十分に理解しておく必要がありますね。

子供にパソコンを使わせる際に注意すべきこと。
・クレジットカード情報は入力しない、させない。
・住所等の個人情報を入力しない、させない。どうしても必要な場合は親が判断する。
・ブラウザの子供向けフィルターを設定する。ブラウザはインターネットエクスプローラーがおすすめ。
・パソコンは親の目が届く所でやらせる。
・インターネットを使用する時は無線LANは使用しないで、親の目の届く所で有線LANを繋いでやらせる。

image0

[C#]System.Net.WebSocketsを試す。その2。サーバー編。

System.Net.WebSocketsを使用してサーバーを作成。
System.Net.WebSocketsには”WebSocketServer”とか分かりやすい名前はなく、クライアントからの待受はSystem.Net.HttpListenerクラスが行います。これはWebSocketのはじめのハンドシェイクはhttpにより行われることからですね。

詳しいことはMSDNの記事に載っています。

Windows 8 のネットワーク接続 Windows 8 と WebSocket プロトコル
http://msdn.microsoft.com/ja-jp/magazine/jj863133.aspx

上記の記事内のサンプルソースもとても参考になります。

エコーサーバーを作成してみる。
以前作成したSuperWebSocketを使用したサーバーと同じ動作をするものを作成してみます。

ソース

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Net;
using System.Net.WebSockets;

using System.Diagnostics;

namespace WsEchoServerForWin8
{
    class Program
    {
        static void Main(string[] args)
        {
            StartServer();
            Console.WriteLine("{0}:Server start.\nPress any key to exit.", DateTime.Now.ToString());
            Console.ReadKey();
            Parallel.ForEach(_client,p=>
            {
                if (p.State == WebSocketState.Open) p.CloseAsync(WebSocketCloseStatus.NormalClosure, "", System.Threading.CancellationToken.None);
            });
        }

        /// <summary>
        /// クライアントのWebSocketインスタンスを格納
        /// </summary>
        static List<WebSocket> _client = new List<WebSocket>();

        /// <summary>
        /// WebSocketサーバースタート
        /// </summary>
        static async void StartServer()
        {
            /// httpListenerで待ち受け
            var httpListener = new HttpListener();
            httpListener.Prefixes.Add("http://192.168.1.10:12345/");
            httpListener.Start();

            while (true)
            {
                /// 接続待機
                var listenerContext = await httpListener.GetContextAsync();
                if (listenerContext.Request.IsWebSocketRequest)
                {
                    /// httpのハンドシェイクがWebSocketならWebSocket接続開始
                    ProcessRequest(listenerContext);
                }
                else
                {
                    /// httpレスポンスを返す
                    listenerContext.Response.StatusCode = 400;
                    listenerContext.Response.Close();
                }
            }
        }
        
        /// <summary>
        /// WebSocket接続毎の処理
        /// </summary>
        /// <param name="listenerContext"></param>
        static async void ProcessRequest(HttpListenerContext listenerContext)
        {
            Console.WriteLine("{0}:New Session:{1}", DateTime.Now.ToString(), listenerContext.Request.RemoteEndPoint.Address.ToString());

            /// WebSocketの接続完了を待機してWebSocketオブジェクトを取得する
            var ws = (await listenerContext.AcceptWebSocketAsync(subProtocol:null)).WebSocket;

            /// 新規クライアントを追加
            _client.Add(ws);

            /// WebSocketの送受信ループ
            while (ws.State == WebSocketState.Open)
            {
                try
                {
                    var buff = new ArraySegment<byte>(new byte[1024]);

                    /// 受信待機
                    var ret = await ws.ReceiveAsync(buff, System.Threading.CancellationToken.None);

                    /// テキスト
                    if (ret.MessageType == WebSocketMessageType.Text)
                    {
                        Console.WriteLine("{0}:String Received:{1}", DateTime.Now.ToString(), listenerContext.Request.RemoteEndPoint.Address.ToString());
                        Console.WriteLine("Message={0}", Encoding.UTF8.GetString(buff.Take(ret.Count).ToArray()));

                        /// 各クライアントへ配信
                        Parallel.ForEach(_client,
                            p => p.SendAsync(new ArraySegment<byte>(buff.Take(ret.Count).ToArray()),
                            WebSocketMessageType.Text,
                            true,
                            System.Threading.CancellationToken.None));
                    }
                    else if(ret.MessageType == WebSocketMessageType.Close) /// クローズ
                    {
                        Console.WriteLine("{0}:Session Close:{1}", DateTime.Now.ToString(), listenerContext.Request.RemoteEndPoint.Address.ToString());
                        break;
                    }
                }
                catch
                {
                    /// 例外 クライアントが異常終了しやがった
                    Console.WriteLine("{0}:Session Abort:{1}", DateTime.Now.ToString(), listenerContext.Request.RemoteEndPoint.Address.ToString());
                    break;
                }
            }

            /// クライアントを除外する
            _client.Remove(ws);
            ws.Dispose();
            
        }
    }
}

実行画面

※実行環境はWindows8で、実行するには管理者権限が必要でした。デバッグ時にはVS自体に管理者権限を付加。ホストPC外からの接続待ちには該当Portに対してファイアーウォールの設定を行う必要がありました。

なぜArraySegmentか、という考察。
送受信時に使用しているArraySegmentについて。ArraySegmentなんて初めて使いましたが。ArraySegmentを使う理由は上部の記事(MSDN)と記事内のサンプルソースを読むと分かってきます。サンプルソースではデータ受信時の処理がループを使用し複数回に分けて送られてくることを想定して作られています。SendAsyncに指定しているendOfMessage(3つめパラメータ)が重要で、要は、大きなデータを分割して送信し、最後の送信だけendOfMessage=trueを指定することでデータ送信の終わりを受信側に知らせることができます。受信側は最後のメッセージを受信した時点で1つのデータを完成させるわけですね。ArraySegmentを使用する理由は1次配列の操作をするためだからだでしょう、楽かどうか別として。

WebSocketライブラリによって動作が違う。
文字列”Hello WebSockets World!!”を3回に分けてSendAsyncを使って送信してみます。

string s = "Hello WebSockets World!!";
var sendData = Encoding.UTF8.GetBytes(s);
await ws.SendAsync(new ArraySegment<byte>(sendData.Take(5).ToArray()), WebSocketMessageType.Text, false, System.Threading.CancellationToken.None); // endOfMessage = false
await ws.SendAsync(new ArraySegment<byte>(sendData.Skip(5).Take(5).ToArray()), WebSocketMessageType.Text, false, System.Threading.CancellationToken.None); // endOfMessage = false
await ws.SendAsync(new ArraySegment<byte>(sendData.Skip(5 + 5).ToArray()), WebSocketMessageType.Text, true, System.Threading.CancellationToken.None); // endOfMessage = true

System.Net.WebSockets.ClientWebSocketの動作。
以前作成したClientWebSocketを使用したクライアントでデータを受信した時のトレース。

Receive
Count = 5
Type  = Text
EndOfMessage= False
Msg   = Hello

Receive
Count = 5
Type  = Text
EndOfMessage= False
Msg   =  WebS

Receive
Count = 14
Type  = Text
EndOfMessage= True
Msg   = ockets World!!

ReceiveAsyncが3回呼ばれます。これらはReceiveAsyncが返す戻り値の値ですが、EndOfMessageのフラグが送信通りになっています。

しかし、WebSocket4Netを使用したクライアントでは受信処理は1度だけで送信文字列は完成された状態で受信できます。WebSocket4NetのMessageReceivedイベントで渡ってくる受信データには文字列が格納されている変数しかなく、最後のデータであるかどうかは知るすべはありません。これはWebSocketの仕様に合わせた各ライブラリの仕様上の動作だと思われますが、そのへんは使用するライブラリによりある程度はコーディングなどでフォローするしかないようです。
ちなみに、WebSocket4Netを使用したクライアントはSendAsync間にSleep(or Task.Delay)を入れてあげないと、中途半端な文字列になったりしてうまく受信できませんでした。

System.Net.WebSockets.ClientWebSocketを使用したクライアントが受信した時。
Img20130312013413
WebSocket4Netを使用したクライアントが受信した時。
Img20130312013648

今回作成したソースはこちら

[C#]非同期でSleep()したい時にはTask.Delay()を使う。

定周期処理を作るとき便利。

使い方は簡単です。
ボタンクリックしたら1秒おきにラベルに0~9までの文字を表示するプログラムを考えます。

Sleep()でやってた処理。

private async void button1_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 10; i++)
    {
        await Task.Run(() => System.Threading.Thread.Sleep(1000));
        label1.Text = i.ToString();
    }
}

Task.Delay()を使う場合。

private async void button1_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 10; i++)
    {
        await Task.Delay(1000);
        label1.Text = i.ToString();
    }
}

実践プログラミング。指定されたIPアドレスに対して1秒周期でPingを送信して死活監視を行う。
以前、同じようなプログラムを作って、えらいめんどくさい思い出があったのですが、async/awaitを使用すると驚くほど簡単に出来ます。

実行画面

ソース

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace async_ping
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
            this.MaximizeBox = false;
        }

        private async void Ping(TextBox tbox)
        {
            Color setcolor = Color.WhiteSmoke;
            if (tbox.Text == "") goto CHANGECOLOR;
            try
            {
                System.Net.IPAddress ipAdr;
                var ipchk = System.Net.IPAddress.TryParse(tbox.Text,out ipAdr);
                if(ipchk ==false) goto CHANGECOLOR;

                var reply = await (new System.Net.NetworkInformation.Ping()).SendPingAsync(ipAdr, 1000);

                if (reply.Status == System.Net.NetworkInformation.IPStatus.Success)
                {
                    setcolor = Color.Lime;
                }
                else
                {
                    setcolor = Color.Red;
                }
            }
            catch
            {
                setcolor = Color.WhiteSmoke;
            }
CHANGECOLOR:
            tbox.BackColor = setcolor;
        }

        private async void Form1_Load(object sender, EventArgs e)
        {
            LoadSaveValue(isLoad: true);

            while (true)
            {
                await Task.Delay(1000);
                foreach (var ctrl in this.Controls)
                {
                    var tbox = ctrl as TextBox;
                    if (tbox != null)
                    {
                        Ping(tbox);
                    }
                }
            }
        }
        private const string SAVEFILE = "savefile.csv";
        private void LoadSaveValue(bool isLoad = false, bool isSave = false)
        {
            if (isLoad)
            {
                if(System.IO.File.Exists(SAVEFILE))
                {
                    var vals = System.IO.File.ReadAllText(SAVEFILE).Split(',');
                    textBox1.Text = vals[0];
                    textBox2.Text = vals[1];
                    textBox3.Text = vals[2];
                    textBox4.Text = vals[3];
                    textBox5.Text = vals[4];
                    textBox6.Text = vals[5];
                    textBox7.Text = vals[6];
                    textBox8.Text = vals[7];
                }
            }
            else if (isSave)
            {
                var s = string.Format("{0},{1},{2},{3},{4},{5},{6},{7}",
                    textBox1.Text,
                    textBox2.Text,
                    textBox3.Text,
                    textBox4.Text,
                    textBox5.Text,
                    textBox6.Text,
                    textBox7.Text,
                    textBox8.Text);
                System.IO.File.WriteAllText(SAVEFILE,s);
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            LoadSaveValue(isSave: true);
        }
    }
}

[C#]System.Net.WebSocketsを試す。その1。ClientWebSocket編。

.NET Framework 4.5からサポートされているWebSocketのクライアント版。
これまでHTML5LabsのWCF WebSocketsを使用してきましたが、こちらは開発がストップ(?)しているようで、WebSocketsのプロトコルバージョンも古かったりします。もし、Windows7でWebSocketsを使用したデスクトップアプリケーションを作成する場合はSuperWebSocketsWebSocket4Netを導入するほうがよいでしょう。

本題のSystem.Net.WebSockets.ClientWebSocketですが、こちらが.NetFrameworkとして実装しているWebSocketsです。サポートOSがWindows8/WindowsServer2012となっておりWindows7はサポートしていません(コーディングはできるが、実行できない)。Windows8は持っていないので体験版を使用してVM上で試してみたい思います。

とりあえずチャットソフト。
とりあえずチャットソフトを作成。ClientWebSocketなので今回はクライアント版。サーバーはとりあえず以前作成したエコーサーバーを使用。

画面
Img20130307144817

動作画面

ソース

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Threading;
using System.Net.WebSockets;

namespace WsForm_WCF_ForWin8
{
    public partial class Form1 : Form
    {
        /// <summary>
        /// Send message buffer size.
        /// </summary>
        const int MessageBufferSize = 256;

        /// <summary>
        /// ClientWebSocket instance.
        /// </summary>
        ClientWebSocket _ws = null;

        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Server connect.
        /// </summary>
        private async void Connect()
        {
            if (_ws == null)
            {
                _ws = new ClientWebSocket();
            }

            if (_ws.State != WebSocketState.Open)
            {
                await _ws.ConnectAsync(new Uri(textBox1.Text), CancellationToken.None);

                while (_ws.State == WebSocketState.Open)
                {
                    var buff = new ArraySegment<byte>(new byte[MessageBufferSize]);
                    var ret = await _ws.ReceiveAsync(buff, CancellationToken.None);
                    listBox1.Items.Add((new UTF8Encoding()).GetString(buff.Take(ret.Count).ToArray()));
                    listBox1.TopIndex = listBox1.Items.Count - 1;
                }
            }
        }

        /// <summary>
        /// Connect button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            Connect();
        }

        /// <summary>
        /// Send message button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            var buff = new ArraySegment<byte>(Encoding.UTF8.GetBytes(textBox2.Text));
            if (_ws.State == WebSocketState.Open)
            {
                _ws.SendAsync(buff, WebSocketMessageType.Text, true, CancellationToken.None);
            }
        }

        /// <summary>
        /// Close websockets.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if ((_ws != null) && (_ws.State == WebSocketState.Open))
            {
                _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
            }
        }
    }
}

果たしてこれで良いのかどうかわかりませんが、細かいレベルの動作についてはおいおい。。。
尚、MSDNのサンプルを参考にしました。
WebSockets middle-tier sample using ClientWebSocket
http://code.msdn.microsoft.com/WebSockets-middle-tier-5b2972ce

全然違うコーディング。
これまでやってきたC#のWebSocketsのAPI(接続、送信、受信、接続断)はイベントハンドラを利用して処理をコーディングしましたが、ClientWebSocketはasync/awaitなAPIなので、コードが全然違います。Eventと違い非同期メソッドなので、その処理を待つ・処理後のコールバックなどは自分でコーディングする必要があります。コールバック的なものはawaitの直下の処理であり、この部分は別スレッドからのUIのアクセスにInvoke()が必要ありません。但し、awaitが使用できるのはasyncメソッド内だけだったり、awaitが指定できる処理はTaskを返すメソッドである必要があったり、色々考えて作る必要がありそうです。うーん、これは慣れるのに時間がかかりそう。。。

今回作成したソースはこちら

[C#]async/awaitの使い方メモ、その1。

今後の.NET開発では必須スキルか。
.NETでの非同期処理の書き方があまりにも色々ありすぎて覚えるのも大変。でも、async/awaitを使用した非同期処理は今後重要なキーワードとなってきそうです。

参考
連載:C# 5.0&VB 11.0新機能「async/await非同期メソッド」入門
http://www.atmarkit.co.jp/ait/subtop/features/da/ap_masterasync_index.html

ボタンをクリックすると1秒間隔でラベルの文字が変更するプログラムを書く。
フォームのボタンをクリックすると1秒間隔で10回、ラベルの文字が変更するプログラムを考えます。

非同期処理を使わない例。
非同期処理の効用を知るために、非同期処理を使わないで処理を書いてみます。

        private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 10; i++)
            {
                System.Threading.Thread.Sleep(1000);
                label1.Text = i.ToString();
            }
        }

実行画面

ボタンクリック後、処理が終わるまでコントロールはフリーズしたようになります。

非同期処理を使う例。
非同期処理をTaskクラスで実装してみます。

        private void button1_Click(object sender, EventArgs e)
        {
            var task = new TaskFactory().StartNew(() =>
                {
                    for (int i = 0; i < 10; i++)
                    {
                        System.Threading.Thread.Sleep(1000);
                        this.Invoke(new Action(() => label1.Text = i.ToString()));
                    }
                });
        }

実行画面

非同期処理を使うことでクリック後もコントロールの操作が可能になります。

async/awaitで非同期処理を書く例。
async/awaitを使用して非同期処理を書いてみます。

        private async void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 10; i++)
            {
                await Task.Run(() => System.Threading.Thread.Sleep(1000));
                label1.Text = i.ToString();
            }
        }

メソッドの定義にasyncキーワードを追加しています。これは非同期メソッドであることを宣言しています。awaitは処理本体に記述する演算子で、単純に言えば非同期で行う処理を示しています。asyncが宣言されたメソッドにはawaitの処理が必要であり(awaitがない場合はコンパイル警告が発生)、基本的にはペアで覚えれば良いと思います。
awaitが指定できる処理にはFuncもしくはActionを実行するTaskを指定します。上記のような書き方をすれば別スレッドからのUI操作にInvokeメソッドが必要ありません。これは非同期処理が別スレッドで動作した後に、再度そのメソッドの続きから始められるようにコンパイラがしてくれているそうです。

ラムダ式の場合は次のように書きます。

        private void button1_Click(object sender, EventArgs e)
        {
            Action func = async () =>
            {
                for (int i = 0; i < 10; i++)
                {
                    await Task.Run(() => System.Threading.Thread.Sleep(1000));
                    label1.Text = i.ToString();
                }
            };

            func();
        }          

まとめ。
async/awaitの書き方はLINQやラムダ式同様、一つの糖衣構文ですね。手軽に非同期処理書けまっせということでしょう。また、WindowsPhoneやタブレットなどが増えて、ユーザーがUIに触れている時間が増えたということと、開発者がこれまで作成できなかった部分というのが広がり、UIをフリーズさせないようにするために非同期処理の重要性が高まったというのが背景にあるのかも。つまり、今後、.NETが提供する時間がかかる系のAPIはasyncメソッドなので、使い方覚えてね!ということのようです。

[上原ひろみ]上原ひろみ 米JAZZ雑誌「ダウンビート」表紙を飾る。

f51356a3053c7c

musicman-net.com 上原ひろみ、日本人では秋吉敏子以来33年ぶり2人目の米ジャズ雑誌「ダウンビート」表紙に
http://www.musicman-net.com/artist/24237.html

ひろみちゃんが日本人としては33年ぶりに米JAZZ雑誌ダウンビートの表紙を飾ったようです。
記事にあるようにダウンビートが行った第60回批評家投票でひろみちゃんがRising Star Keyboard部門で1位を獲得したのは知っていました。
今回はキーボード部門でしたが、いつかはPiano部門で1位を獲って欲しいですね♪

3351097655_c0124393aa gigil_L

ああ、なかなかキーボードを弾いている写真が見当たらない~♫
TimeControl,BeyondStandardのときは今よりもいっぱい弾いていましたね♪