カテゴリ:.NET( 18 )
.NET4.5におけるasync/awaitを使用した非同期処理
VS2012以降で.NET4.5をターゲットにした場合,async/awaitを使用した非同期処理を使用できる

サンプルコード

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

namespace AsyncSample
{
class Program
{

static void Main(string[] args)
{
Console.WriteLine("Main...");
Task t = Test();
Console.WriteLine("Main...Wait");
t.Wait();
Console.WriteLine("Main...Wait/end");
Console.ReadLine();
}

static async Task Test()
{
Console.WriteLine("Test...");
int length = await AccessTheWebAsync();
Console.WriteLine("Test..." + length.ToString());
return;
}

static async Task<int> AccessTheWebAsync()
{
Console.WriteLine("AccessTheWebAsync()");
// You need to add a reference to System.Net.Http to declare client.
HttpClient client = new HttpClient();

// GetStringAsync returns a Task<string>. That means that when you await the
// task you'll get a string (urlContents).
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();

// The await operator suspends AccessTheWebAsync.
// - AccessTheWebAsync can't continue until getStringTask is complete.
// - Meanwhile, control returns to the caller of AccessTheWebAsync.
// - Control resumes here when getStringTask is complete.
// - The await operator then retrieves the string result from getStringTask.
Console.WriteLine("AccessTheWebAsync()... await getStringTask");
string urlContents = await getStringTask;
Console.WriteLine("AccessTheWebAsync()... await getStringTask End");

// The return statement specifies an integer result.
// Any methods that are awaiting AccessTheWebAsync retrieve the length value.
return urlContents.Length;
}

static void DoIndependentWork()
{
Console.WriteLine("DoIndependentWork();");
}
}
}



実行結果

Main...
Test...
AccessTheWebAsync()
DoIndependentWork();
AccessTheWebAsync()... await getStringTask
Main...Wait
AccessTheWebAsync()... await getStringTask End
Test...25204
Main...Wait/end


解説
メソッドについているasyncは非同期を表す修飾子。この戻り値はvoidまたはTaskになる。
http://msdn.microsoft.com/ja-jp/library/hh156513.aspx
戻り値を返したい場合,Task<戻り値の型>となる。

メソッドを呼び出す際に指定している await 演算子は、待機中のタスクが完了するまでメソッドの実行を中断する。
http://msdn.microsoft.com/ja-jp/library/hh156528.aspx

Test() メソッド中にAccessTheWebAsyncメソッドをasyncをつけて読んでいるが、これは、AccessTheWebAsyncの処理が終了するまで
待機することを表す。
awaitを用いて中断している場合は、呼び出し元に制御を返し、処理が完了したら中断している箇所から制御が再開する。

Wait()も制御を中断するが、呼び出し元に制御がもどることはない。
たとえば、以下のコードを置き換える

//int length = await AccessTheWebAsync();
Task<int> t = AccessTheWebAsync();
t.Wait();
int length = t.Result;

この場合の実行結果は以下のようになり、Mainに制御がもどらずに、Test()中で中断していることがわかる。

Main...
Test...
AccessTheWebAsync()
DoIndependentWork();
AccessTheWebAsync()... await getStringTask
AccessTheWebAsync()... await getStringTask End
Test...25204
Main...Wait
Main...Wait/end


なお、VS2012以降(C#5.0)なら.NET4.5以外をターゲットにしてもasync/awaitを使用した非同期処理を使用できる。
http://xin9le.net/articles/81

参考
http://msdn.microsoft.com/ja-jp/library/hh191443.aspx

[PR]
by mima_ita | 2014-07-02 00:46 | .NET
.NETでTwitterを検索する
目的
.NETを用いてTwitterの検索を行う。

環境
Windows7
VisualStudio Express 2013 for Windows DeskTop

LINQ to Twitter
LINQ to TwitterはLINQを用いてTwitterの操作を行える。
http://linqtotwitter.codeplex.com/

このライブラリSystem.Net.Http.Primitivesに依存しているので、以下のようにインストールすること。

1. プロジェクトの参照設定でNuGetパッケージの管理を選択する
b0232065_00401670.png
2.Microsoft HTTP Client Libraryをインストールする
b0232065_00405023.png
AccessTokenとAccessTokenSecretの取得方法
クライアントアプリケーションでAccessTokenとAccessTokenSecretを取得するには次のように認証用のURLを開いて、PINコードを取得して、それを使用して認証を行う。

C#でOAuthでTwitter 
http://d.hatena.ne.jp/nojima718/20100129/1264792636

なお、CONSUMERKEY,CONSUMERSECRETはTwitterDeveloperでアプリケーションを追加してキーを発行する。
https://dev.twitter.com/

LINQ to Twitterでツイートを検索する

var singleAuth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore
{
ConsumerKey = this.auth.ConsumerKey,
ConsumerSecret = this.auth.ConsumerSecret ,
AccessToken = this.auth.AccessToken ,
AccessTokenSecret = this.auth.AccessTokenSecret
}
};
var str = "";

var twitterCtx = new TwitterContext(singleAuth);
var searchResponse =
await
(from search in twitterCtx.Search
where search.Type == SearchType.Search &&
search.Query == txtSearch.Text &&
search.Count == 100
select search)
.SingleOrDefaultAsync();

if (searchResponse != null && searchResponse.Statuses != null)
searchResponse.Statuses.ForEach(tweet =>
str += String.Format("CreatedAt: {0}, User: {1}, Tweet: {2}\r\n",
tweet.CreatedAt,
tweet.User.ScreenNameResponse,
tweet.Text));

txtLog.Text = str;


[PR]
by mima_ita | 2014-06-29 00:49 | .NET
MicrosoftReportを用いた帳票の作成
MicroSoftレポートとは?
MicrosoftレポートとはVisual Studioが.NETでの帳票の作成をサポートするために提供しているコントロールです。レポートのデザイン機能と、アプリケーションでレポート処理および表示をするためのReportViewerコントロールが提供されています。
次の図はMicrosoftレポートが、どのように帳票を作成するかを簡単に表したものです。

b0232065_21471767.png

データソース:
アプリケーションが使用するデータのことで特にアプリケーションで操作する必要のあることが明確なデータです。

レポート定義:
帳票のレイアウトや、どのデータを作成するかをXMLで記述したものですVisual Studioのレポートデザイナを使用して変更が可能です。

ReportViewerコントロール
データセットとレポート定義より帳票を作成します。

どんな帳票がつくれるの?


Excelのような一覧形式
b0232065_21480489.png
Excelのように一覧としてデータを表示します。
各フィールドでは書式の指定や数式の指定が行えます。必要であれば、開発者は自分の目的にあった数式を自作して利用することもできます。

自由フォーマットの単票形式
b0232065_21484210.png
単票としてデータの詳細を自由なフォーマットで表現します。
数字や、文字だけでなく、画像も使用できます

グラフとか
b0232065_21490979.png
データをグラフとして表示することができます。
棒グラフだけでなく、折れ線グラフや円グラフなど、様々な表現方法が実現できます。



チュートリアルないの?
Microsoftのページにあるけどバージョンのせいか、なんかしらないけど、チュートリアルが動きません。なので自作しました。

http://needtec.sakura.ne.jp/doc/msreport.pdf

http://needtec.sakura.ne.jp/doc/msreport.docx

おそらく、VisualStudio2013でMsレポート始める日本人はこれが一番楽だと思います。

(日本語の資料あんまりない。CodeProjectでわかりやすい資料もVS2008だったりする。マイクロソフトの公式のチュートリアルはサンプルDBすら構築させない構え・・・ヽ(゚`Д´゚)ノ゚。ウワァァァン!!


[PR]
by mima_ita | 2013-12-18 22:04 | .NET
XPSファイルを画像に変換する
XpsToImgはXPSファイルを画像に変換します。

ExcelXpsToImg.zip

動作環境
.NET Framework3.0が必要

使い方

XpsToImg XpsFilePath OutputFolder PrefixFileName dpi

  • XpsFilePath : 変換対象のXpsファイル ex:c:\test.xps
  • OutputFolder : 出力先フォルダ ex:c:\out
  • PrefixFileName : 出力するファイルの接頭文字 ex:page
  • dpi: 画像データの精度 ex:96



More
[PR]
by mima_ita | 2013-12-14 18:04 | .NET
.NETのCLRは文字をUTF16で扱う
C#でソースコードをUTF8で扱おうが、アセンブラをCP932で書こうが、UTF16になっている。

C#の例
// hello.cs を utf-8で保存する
// コンパイル方法
// csc hello.cs
// A Hello World! program in C#
using System;
namespace HelloWorld
{
    class Hello
    {
        static void Main()
        {
            System.Console.WriteLine("熱風!疾風!サイバスター!!!!");
        }
    }
}

ここで作成されたアセンブリをildasmで逆コンパイルすると、文字列は次のようになる。
.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // コード サイズ       13 (0xd)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      bytearray (B1 71 A8 98 01 FF BE 75 A8 98 01 FF B5 30 A4 30   // .q.....u.....0.0
                                  D0 30 B9 30 BF 30 FC 30 21 00 21 00 21 00 21 00 ) // .0.0.0.0!.!.!.!.
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  ret
} // end of method Hello::Main
一文字目の0xB171はリトルエンディアンなので0x71B1となる。
それはUnicode対応文字コード表によると「熱」を表す。


アセンブラの例
//hello_asm.asmとしてCP932で保存する.
// UNICODEはおけ―だがUTF8だと化ける。
//コンパイル方法
// ilasm hello_asm.asm
.assembly extern mscorlib { }
.assembly test { }

.method static void Main() cil managed {
    .entrypoint
    ldstr "熱風!疾風!サイバスター!!!!"
    call void [mscorlib]System.Console::WriteLine(string)
    ret
}

ここで作成されたアセンブリをildasmで逆コンパイルすると、文字列は次のようになる。

.method privatescope static void  Main$PST06000001() cil managed
{
  .entrypoint
  // コード サイズ       11 (0xb)
  .maxstack  8
  IL_0000:  ldstr      bytearray (B1 71 A8 98 01 FF BE 75 A8 98 01 FF B5 30 A4 30   // .q.....u.....0.0
                                  D0 30 B9 30 BF 30 FC 30 21 00 21 00 21 00 21 00 ) // .0.0.0.0!.!.!.!.
  IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000a:  ret
} // end of method 'Global Functions'::Main

一文字目は0xB171 つまり、リトルエンディアンなのでUTF16の「熱」になる


つまり、C#だろうが、アセンブラだろうが、コンパイルして作成された文字はUTF16で処理されることが確認できる。


[PR]
by mima_ita | 2013-12-11 00:38 | .NET
.NETにおけるLarge Object Heap(LOH)の使用について
.NETのメモリ領域には大きく2種類存在します。
1つは80,000バイト未満のオブジェクトを格納するSmall Object Heap(SOH)と、
80,000バイト以上のオブジェクトを格納するLarge Object Heap(LOH)です。


この80,000バイトというサイズは将来的に変わる可能性のある数値であり、定数として考えるべきではありません。


ガベージコレクションを行った場合、SOHではコンパクションが発生して、空いている領域を詰めてメモリの中身を再配置します。
LOHはガベージコレクションにより、コンパクションは発生せず、メモリの再配置はしません。
このことは、メモリの断片化を生み、OutOfMemoryExceptionの例外を発生させることを意味します。


Andrew Hunterは、この件に関しての最悪の場合の事例を再現したテストプログラムを公開しています。

The Dangers of the Large Object Heap
https://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/


.NETのガベージコレクションはヒープの末尾に領域を確保する傾向があります。そのため、メモリの途中で十分な空き容量があっても、メモリの確保に失敗することがあります。
この記事では、本来なら何百MB以上利用できるのにもかかわらず、20MBしか使用できなくなりました。



実は、この結果は.NET4.0において劇的に改善されました。



以下に同様のプログラムで行った実験結果を示します。

実験環境
VisualStudio2013 Expressでx86のアプリケーションを作成
Windows7 SP1 64bit
メモリ 4.00GB
結果

v2.0 v3.0 v3.5 v4.0 v4.5 v4.5.1
With large bloks 19Mb 19Mb 20Mb 1546Mb 1546Mb 1439Mb
With large bloks,
frequent garbage collection
23Mb 23Mb 23Mb 1570Mb 1570Mb 1546Mb
Only small block 1572Mb 1620Mb 1588Mb 1643Mb 1643Mb 1643Mb
With large blocks,
large blocks not growing
1375Mb 1596Mb 1419Mb 1636Mb 1620Mb 1565Mb


参考:
C++のアンマネージドコードで「With large bloks」を行った場合の結果
 2020MB

結果をみると.NET4.0から劇的にメモリの確保の効率がよくなっていることがわかります。
ただし、最終的に断片化が解決したわけではありません。


なお、.NET4.5.1ではLOHの領域にたいするコンパクションを指示する命令が追加されました。

Using System;
Using System.Runtime;

// LOHに対するコンパクションを要求
GCSettings.LOHCompactionMode =
GCLargeObjectHeapCompactionMode.CompactOnce;

// GCが発生してLOHがコンパクションされる
GC.Collect():
この設定でGCが発生した場合、停止時間が長くなる可能性が極めて高いので使用には注意を払ってください。












More
[PR]
by mima_ita | 2013-12-03 22:02 | .NET
.NETにおけるガベージコレクションについて
.NETにおけるマネージヒープとガベージコレクションについての説明。


Excelmanagedheap.pdfExcelmanagedheap.pptx

書きかけ。

[PR]
by mima_ita | 2013-12-02 23:59 | .NET
.NETにおけるオブジェクトの生存期間
.NETにおけるオブジェクトの生存期間は、参照されている間です。
たとえば、以下のようなMainメソッドあるとします。

using System;
using System.Threading;

namespace TimerTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Timer t = new Timer(TimerCallback, null, 0, 2000);

            // タイミングA
            Console.ReadLine();

            // オブジェクトtの参照
            Console.WriteLine(t.ToString());

            // タイミングB
            Console.ReadLine();

        }

        private static void TimerCallback(Object o)
        {
            Console.WriteLine("Callback" + DateTime.Now);
            GC.Collect();
        }

    }
}


オブジェクトtの生存期間はどこまでか?
Mainメソッドが終了するまでは保障されません


最後にオブジェクトを参照したところまでしか保証されません。


つまり、タイミングAにおいてはオブジェクトtは存在しますが、タイミングBおいてオブジェクトtの存在は保障されないのです。
オブジェクトtを参照したのちにガベージコレクションが実行されたとしたら、もはやオブジェクトtは存在しなくなります。


ちなみにこのコードはReleaseビルド時とDebugビルド時に挙動が変わります。Debugビルドを行った場合、JITコンパイラはメソッドの末尾まで恣意的にオブジェクトの生存期間を延ばします


このことは我々に「テストはReleaseビルドでやるべきだ」という教訓をあたえてくれるでしょう。


なお、ReadLine()の後もオブジェクトtが欲しい場合、Mainメソッドの最後に以下を記述すべきです。

       t.Dispose();



[PR]
by mima_ita | 2013-12-02 14:00 | .NET
.NETにおける64ビットプロセスと32ビットプロセスについて
■1プロセスにおける32ビットと64ビットの混在
ネィティブアプリケーションの場合、プラットフォームの異なるExeとDllは共存できません。
  • x64のExeと x64のDLL ⇒動作する
  • x86のExeと x86のDLL ⇒動作する
  • x64のExeと x86のDLL ⇒動作しない
  • x86のExeと x64のDLL ⇒動作しない

ネイティブアプリケーションはビルド時に、どちらにするか指定してビルドする必要があります。


.NET の場合、ビルド時にプラットフォームに"x86","x64"以外に"Any CPU"が選択できます。

Any CPUを選択した場合次のような挙動になります。
  • Exeの場合、OSが32ビットの場合、32ビットのプロセスとして動作します。
  • Exeの場合、OSが64ビットの場合、64ビットのプロセスとして動作します。
  • DLLの場合、呼び出したExeが32ビットで動作している場合、32ビットで動作します。
  • DLLの場合、呼び出したExeが64ビットで動作している場合、64ビットで動作します。


Any CPUでExeを作成した場合、64bitOSで32bitプロセスが動作できません。
これを解決するには、以下に述べているように、CorFlags を用いてExeを修正する必要があります。
参考:64bitOSでAnyCPUでコンパイルした32bitプロセスを動かす


この問題を解決するために、.NET4.5以降では「32ビットを優先にする」というオプションを指定できます。
これはAny CPUではありますが、32bitで動作が可能な場合は32bitで動作します。

■プラットフォームの異なるプロセスの相互運用

1つのプロセスで32bitと64bitは混在して動作しないことは説明しました。
しかし、64ビット版のWindowsでは64bitプロセスと32ビットプロセス間のプロシージャコールはサポートされています。
つまり64ビットのアウトプロセスのCOMサーバーは32ビットのクライアントと通信でき、逆に32ビットのアウトプロセスのCOMサーバーは64ビットのクライアントと通信できます。

.NETでCOMサーバーを作成するのは下記を参考にしてください。
How to develop an out-of-process COM component by using Visual C++, Visual C#, or Visual Basic .NET



実際にCOMサーバーを作成するには、上記のページからCSExeCOMServerをダウンロードします。

プロジェクトのプロパティーを以下のいづれかに修正してください。

32ビットのアウトプロセスを作成する場合

「ビルド」タブのプラットフォームターゲット
x86


「ビルドイベント」タブの「ビルド後に実行するコマンドライン」
C:\Windows\Microsoft.NET\Framework\v2.0.50727\regasm.exe /tlb "$(TargetPath)"


64ビットのアウトプロセスを作成する場合

「ビルド」タブのプラットフォームターゲット
x64


「ビルドイベント」タブの「ビルド後に実行するコマンドライン」
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\regasm.exe /tlb "$(TargetPath)"

実際にビルドしてCOMを登録すると、32ビットのCOMサーバー、または64ビットのCOMサーバーどちらであっても、32ビット、64ビットの両方のクライアントから使用できることがわかります。


詳しい詳細は、ダウンロードしたReadme.txtを参考にしてください。実際の作り方が記述してあります。



なお、アウトプロセスのCOMサーバーなので以下のようにスタティックな変数を使用すれば、異なるプラットフォームのプロセス間でのデータの共有が可能です。

    public class CSSimpleObject : ReferenceCountedObject, ICSSimpleObject
    {
   
        private static int _staticVal = 0;
        private static Object thisLock = new Object();
       public int StaticValue
        {
            get
            {
                return _staticVal;
            }
            set
            {
                lock(thisLock)
                {
                    _staticVal = value;
                }
            }
        }





WindowsではこのようにアウトプロセスのCOMサーバーを利用することにより、異なるプラットフォームのプラットフォームであっても、労力をかけずに連携できると思います。

UNIXのgccで32bitプロセスと64bitプロセスの連携やったときは、きつかった。


■プラットフォームターゲットを明示する理由

プラットフォームターゲットに「Any CPU」を選択してはいけません。
COMオブジェクト作成中にアプリケーションがハングします。
PEヘッダ中のIMAGE_NT_HEADERS.FileHeader.Machineに IMAGE_FILE_MACHINE_I386がセットされているためです。
64ビットOSの場合、COMとしては32ビットとして動作することを期待していますが、実際64bitとして動作してしまうのです。

この値はVisualStdioに付属しているbumpbinを用いて確認できます。以下のようなコマンドを実行してください。

dumpbin CSExeCOMServer.exe /headers

この結果を見てみましょう

x86を明示した場合。
File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
             14C machine (x86)
               3 number of sections

x64を明示した場合。
File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
            8664 machine (x64)
               2 number of sections

Any Cpu
File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
             14C machine (x86)
               3 number of sections
              

Any Cpuのヘッダにはx86と記述されていますが、実際、.NETとしては64ビットで動作するために不整合が出てしまいます。
アウトプロセスのCOMを作成する場合は、プラットフォームは絶対に指定してビルドをしなければなりません。





[PR]
by mima_ita | 2013-12-01 02:50 | .NET
VisualStdio2012でバッチビルドを行う方法
VisualStdioではバッチビルドという複数の構成を一度でビルドできる機能がありますが、デフォルトでこの機能はメニューに表示されません。

b0232065_18554909.png
1.メニューバーを右クリックして「カスタマイズ」というボタンを押す
b0232065_18561912.png
2.「コマンド」タブを選択して「メニューバー」の「ビルド」を選択する。
 そして、コントロール中でバッチコマンドを入れたい場所を選択してから、「コマンド追加ボタン」をおす
b0232065_19001793.png

3.カテゴリ中の「ビルド」を選択して、コマンドのなかにある「バッチビルド」を選択する。
b0232065_18592904.png
4.すると、コントロール中にバッチビルドが表示されるのでOKをおして画面を終了する。
b0232065_19031609.png
5.メニューでバッチビルドを選択する
b0232065_19035017.png
6.ビルドしたい構成を選択すると、選択したビルドがすべてビルドできる
b0232065_19041782.png



[PR]
by mima_ita | 2013-11-30 19:05 | .NET



実験ですお
検索
カテゴリ
最新の記事
.NET4.5におけるasy..
at 2014-07-02 00:46
.NETでTwitterを検..
at 2014-06-29 00:49
Redmineのプラグインで..
at 2014-06-28 03:29
IO.popenのwrite..
at 2014-06-28 03:25
RedmineのWikiでU..
at 2014-06-28 03:16
以前の記事
最新のトラックバック
その他のジャンル
ブログパーツ