きなこもち.net

.NET Framework × UiPath,Orchestrator × Azure × AWS × Angularなどの忘備録

UWP × Windows.Graphics.Capture × スクリーンショットの取得サンプルを作ってみた

この記事の目的

この記事では、
UWPでスクリーンショットを取得するまでの手順をまとめること
を目的としています。

本題

★背景

WPFスクリーンショットを取得するアプリを作っていましたが、
配布をすることと、興味があったことから、
UWPで同じことができるアプリを作ってみようと思ったのがきっかけです。

UWPでスクリーンショットを取得する方法を調べてみると、Docsでちょうどよい記事を見つけました。
docs.microsoft.com


よく読んでみると、UWPでスクリーンショットを取得する機能は、
Windows 10 Version 1803で新しく追加された機能らしいです。

タイミングが良すぎましたw
記事に従ってちゃかっと実装完了♪



とか思っていましたが、そう簡単にいかなかったです。
ということで、公式の手順と、自分なりに試行錯誤した手順をまとめてみました。



★準備・その1

当たり前ですが、Visual Studio を開き、UWPのプロジェクトを作成しておきます。
何でもいいですが、わかりやすいように空白のアプリを選択します。
f:id:kinakomotitti:20180523220257p:plain


★準備・その2

ここは、公式の手順にある通りです。

1. Right-click Package.appxmanifest in the Solution Explorer.
2. Select Open With...
3. Choose XML (Text) Editor.
4. Select OK.
5. In the Package node, add the following attribute: xmlns:uap6="http://schemas.microsoft.com/appx/manifest/uap/windows10/6"
6. Also in the Package node, add the following to the IgnorableNamespaces attribute: uap6
7. In the Capabilities node, add the following element: 

5.6.を実装後は以下のようになります。
f:id:kinakomotitti:20180523220304p:plain



7.を実装後は以下のようになります。
f:id:kinakomotitti:20180523220311p:plain



マニュフェストファイルって、コードを直接編集するのですね。
GUIからしか操作したことがなかったので、少し新鮮な気持ちでした。


★準備・その3

対象のプロジェクトに、NugetでWin2D.uwpをインストールします。
f:id:kinakomotitti:20180523220325p:plain



★サンプルコード

MainPage.xaml.csに以下のコードを追加します。
長いコードなのはご容赦ください。。。
公式コードをベースとしていますが、
エラーが出ていたところを修正しています。
また、出力結果の確認をするために、スクリーンショットpng形式で出力する実装を追加しました。

using Microsoft.Graphics.Canvas;
using System;
using System.Threading.Tasks;
using Windows.Graphics;
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX;
using Windows.Storage;
using Windows.UI.Composition;
using Windows.UI.Xaml.Controls;

namespace App1
{
    /// <summary>
    /// それ自体で使用できる空白ページまたはフレーム内に移動できる空白ページ。
    /// </summary>
    public sealed partial class MainPage : Page
    {
        // Capture API objects.
        private SizeInt32 _lastSize;
        public GraphicsCaptureItem item;
        private GraphicsCaptureItem _item;
        private Direct3D11CaptureFramePool _framePool;
        private GraphicsCaptureSession _session;

        // Non-API related members.
        private CanvasDevice _canvasDevice;
        private CompositionDrawingSurface _surface;

        public MainPage()
        {
            this.InitializeComponent();
            StartCaptureAsync();
        }

        public async Task StartCaptureAsync()
        {
            // The GraphicsCapturePicker follows the same pattern the 
            // file pickers do. 
            var picker = new GraphicsCapturePicker();
            GraphicsCaptureItem item = await picker.PickSingleItemAsync();

            // The item may be null if the user dismissed the 
            // control without making a selection or hit Cancel. 
            if (item != null)
            {
                StartCaptureInternal(item);
            }
        }

        private void StartCaptureInternal(GraphicsCaptureItem item)
        {
            // Stop the previous capture if we had one.
            StopCapture();

            _item = item;
            _lastSize = _item.Size;
   
            //初期化がないとPoolのCreateで落ちるので追加。
            _canvasDevice = new CanvasDevice(); 
            _framePool = Direct3D11CaptureFramePool.Create(
               _canvasDevice, // D3D device 
               DirectXPixelFormat.B8G8R8A8UIntNormalized, // Pixel format 
               2, // Number of frames 
               _item.Size); // Size of the buffers 

            _framePool.FrameArrived += (s, a) =>
            {
                // The FrameArrived event is raised for every frame on the thread
                // that created the Direct3D11CaptureFramePool. This means we 
                // don't have to do a null-check here, as we know we're the only 
                // one dequeueing frames in our application.  

                // NOTE: Disposing the frame retires it and returns  
                // the buffer to the pool.

                using (var frame = _framePool.TryGetNextFrame())
                {
                    ProcessFrame(frame);
                }
            };

            _item.Closed += (s, a) =>
            {
                StopCapture();
            };

            _session = _framePool.CreateCaptureSession(_item);
            _session.StartCapture();
        }

        public void StopCapture()
        {
            _session?.Dispose();
            _framePool?.Dispose();
            _item = null;
            _session = null;
            _framePool = null;
        }

        private async Task ProcessFrame(Direct3D11CaptureFrame frame)
        {
            // Resize and device-lost leverage the same function on the
            // Direct3D11CaptureFramePool. Refactoring it this way avoids 
            // throwing in the catch block below (device creation could always 
            // fail) along with ensuring that resize completes successfully and 
            // isn’t vulnerable to device-lost.   
            bool needsReset = false;
            bool recreateDevice = false;

            if ((frame.ContentSize.Width != _lastSize.Width) ||
                (frame.ContentSize.Height != _lastSize.Height))
            {
                needsReset = true;
                _lastSize = frame.ContentSize;
            }

            try
            {
                // Take the D3D11 surface and draw it into a  
                // Composition surface.

                // Convert our D3D11 surface into a Win2D object.
                var canvasBitmap = CanvasBitmap.CreateFromDirect3D11Surface(
                    _canvasDevice,
                    frame.Surface);

               //出力結果を確認するために、ファイルを「Pictures」フォルダに出力するように変更。
               //ここから
                string filename = $"{ DateTime.Now.ToString("yyyMMdd_HHmmss.fffffff")}.png";
                StorageFolder pictureFolder = KnownFolders.SavedPictures;
                var file = await pictureFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
               //ここまで

                using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
                {
                    await canvasBitmap.SaveAsync(fileStream, CanvasBitmapFileFormat.Png, 1f);
                }
                // Helper that handles the drawing for us, not shown. 
                //FillSurfaceWithBitmap(_surface, canvasBitmap);
            }
            // This is the device-lost convention for Win2D.
            catch (Exception e) when (_canvasDevice.IsDeviceLost(e.HResult))
            {
                // We lost our graphics device. Recreate it and reset 
                // our Direct3D11CaptureFramePool.  
                needsReset = true;
                recreateDevice = true;
            }

            if (needsReset)
            {
                ResetFramePool(frame.ContentSize, recreateDevice);
            }
        }
       //公式コードでは、第一引数のsizeは「Vector2」型で定義されていましたが、
  //コンパイルが通らないので、「SizeInt32」型に変更しました。
        private void ResetFramePool(SizeInt32 size, bool recreateDevice)
        {
            do
            {
                try
                {
                    if (recreateDevice)
                    {
                        _canvasDevice = new CanvasDevice();
                    }

                    _framePool.Recreate(
                        _canvasDevice,
                        DirectXPixelFormat.B8G8R8A8UIntNormalized,
                        2,
                        size);
                }
                // This is the device-lost convention for Win2D.
                catch (Exception e) when (_canvasDevice.IsDeviceLost(e.HResult))
                {
                    _canvasDevice = null;
                    recreateDevice = true;
                }
            } while (_canvasDevice == null);
        }
    }
}

まとめ

UWPでスクリーンショットが取得できる。
スクリーンショット機能は、Windows10 1803から。
Windows10のバージョンに合わせて、SDKのインストールも忘れずに行う必要がある。

C# Interactive × 長い文字列 × Clipbordにコピーして使ってみた

この記事の目的

この記事では、
C#Interractiveで長い文字列を使うときのコツをまとめること
を目的としています。

本題

★問題になっていること

C# Interactiveは、C#を対話的に使うことができ、とても便利です。
ただ、長い文字列を表示するとき、以下のように「…」で省略されます。

new string('a', 10000)
//output:
//"aaaaaaaa <中略> aaaaaaaaaaaa...


対話的に処理を行っていき、
処理の最後に長い文字列をコピーしてどこかに貼り付けようとしたとき、
肝心の文字が省略されてしまっては元も子もありませんw
今回は、この問題の解決法をメモしていきます。


★解決方法

【解決法】クリップボードにコピーする
値を選択して右クリック→コピーするのではなく、
C# Interactiveの中でクリップボードにコピーするコードを実行します。
例は以下の通りです。

 string target = new string('A', 100000); 
 #r "System.Windows.Presentation"  
 System.Windows.Clipboard.SetText(target);

これで、文字列のもれなくクリップボードにコピーすることができます。



★そもそもことの発端は?

今回の問題に直面したのは、アプリのテストを行っているときでした。
テストのため、base64形式に変換したファイルデータが必要でした。
複数回必要になるデータであれば、コンソールアプリを作ろうと思ったのですが、
初めの数回分のデータがあれば事足りたので、わざわざ作るのも・・・


ということで、C# Interactiveでサクッとデータを作ることにしました。

そして、そこで長い文字列のコピーという問題に出会いましたw
C# Interactiveで”長そうな文字列”を使うときには注意が必要ですね( ゚Д゚)


★【補足情報】最大表示文字数について

何文字まで「…」なしで表示することができるか検証してみました。
※環境の違いによるものは考慮していません。
※ダブルクォーテーション及び、”>”記号や空白については文字数カウントに含めていません。

new string('a', 1000)
//表示結果:〇
//"aaaaaaaa <中略> aaaaaaaaaaaa

new string('a', 1022)
//表示結果:〇
//"aaaaaaaa <中略> aaaaaaaaaaaa

new string('a', 1023)
//表示結果:×
//"aaaaaaaa <中略> aaaaaaaaaaaa...

new string('a', 1024)
//表示結果:×
//"aaaaaaaa <中略> aaaaaaaaaaaa…

検証結果:
1023文字まではすべての文字が表示されます。
ただし、1023文字以降は「…」で省略されます。
※境界値である1023文字については、すべての文字が表示され、「…」も表示されます。

まとめ

C# Interactiveはやっぱり便利だった。
表示できる文字列は1023文字まで!
それを超える文字を表示、コピーしたいときは、Clipboardへ!

C# × for文 × カウンターについての間違った認識を正してみた

この記事の目的

この記事では、
自分が持っていたfor文についての間違った認識を正すこと
を目的としています。

本題

★基本のき!for文の書き方

C#を初めてすぐにであうことになる基本的な構文に「for文」があります。
Visual Studioコードスニペット機能によって、
[for] + [tabキー] + [tabキー]
と打てば 以下のように入力することができます。

for (int i = 0; i < length; i++)
{

}

コードスニペットを多用することで、for文の書き方を忘れてしまうことが多々ありますがそれは別の話・・・)
上記のコードのように、for文では、カウンター( i )を利用して繰り返し処理を実現します。
カウンターをインクリメントもしくは、デクリメントし、
定義した条件( i < length )がfalseになったときに繰り返し処理を終え、その後の処理へ進みます。


Log4netのとあるクラスにて・・・

log4netのコードを読みつつ実装を学んでいたところ、以下のコードに出会いました。

//Logger.cs
virtual public Level EffectiveLevel
{
	get 
	{
		for(Logger c = this; c != null; c = c.m_parent) 
		{
			Level level = c.m_level;

			// Casting level to Object for performance, otherwise the overloaded operator is called
			if ((object)level != null) 
			{
				return level;
			}
		}
		return null; // If reached will cause an NullPointerException.
	}
}

個人的に衝撃的だったのはfor(Logger c = this; c != null; c = c.m_parent) の部分です。


カウンターがint型じゃないのです(*´Д`)


ここでは、カウンターに「今のLoggerクラスのインスタンス(自分自身)」を定義しています。
Loggerクラスでは、親のLoggerクラスのインスタンスをm_parent変数に格納しています。
イメージとしては以下のようなものになります。

Logger(親A)
m_parent = null
└─Logger(親B)
m_parent = Logger(親A)
└─Logger(実行中のLogger)
m_parent = Logger(親B)


上記の状態のとき、

  1. 開始を自分自身に設定し、(Logger c = this)
  2. 次の値として今のLoggerの親を指定する(c = c.m_parent)
  3. 親がいなくなったらループを抜ける(c != null)

という条件のfor文を実装することができます。


★正しい考え方を整理

MSDNには以下のように記載されています。
for (C# リファレンス) | Microsoft Docs

for ループを使うと、指定した式が false と評価されるまで、ステートメントまたはステートメント ブロックを繰り返し実行することができます。 この種類のループは、配列の反復処理などループの反復回数が事前にわかっている用途に使用します。

class ForLoopTest 
{
    static void Main() 
    {
        for (int i = 1; i <= 5; i++)
        {
            Console.WriteLine(i);
        }
    }
}

まぁ、どこにもinit-expressionがintであるとは書かれていませんね(*´Д`)


まとめ

今回log4netさんに教えていただいた自分の過ちは、・・・

for文 → カウンター → int型しか指定できない

という間違った考え方でした。
同じように間違えて覚えている初心者の開発者を見つけたらこそっと指摘してあげてください(=_=)

Visual Studio 2017 × 形式を選択して貼り付け × 「編集」メニューに表示されない問題に対応してみた

以前書いたブログで、Jsonをクラスに変換するVisual Studioの機能を取り上げました。

kinakomotitti.hatenablog.com


久しぶりに使ってみようとしたらこの機能が表示されていませんでした。
その対応を忘備録として残しておきます。

背景

PCのリプレースに伴い、Visual Studio 2017をクリーンインストールした。
クリーンインストールする際、ケチって「.NET デスクトップ開発」機能だけをインストールした。
f:id:kinakomotitti:20180416230409p:plain

対応

形式を選択して貼り付け機能をメニューに表示するためには、「ASP.NETとWeb開発」機能が必要です。
f:id:kinakomotitti:20180416230731p:plain

上記機能をインストールしたら以下のようにメニューに表示することができました。
f:id:kinakomotitti:20180416230451p:plain

まとめと反省

形式を選択して貼り付け機能をメニューに表示するためには、ASP.NETとWeb開発」機能が必要。
ASP.NETとWeb開発」だけをインストールしても4GBしかコストはかからないので、リソースをケチらずインストールするようにします。

Windows × スレッド × 基本的なことについてまとめてみた

この記事の目的

この記事では、
スレッドの概要についてまとめること
を目的としています。
※以下の書籍を参考に勉強した結果のアウトプットとなります。

プログラミング.NET Framework 第4版 (Microsoft Press) 単行本 – 2013/10/10
Jeffrey Richter (著), 藤原 雄介 (翻訳)

アジェンダ

  1. スレッドってなに?
  2. どんな時に使う?
  3. 使うときの注意点は?
  4. 実際の使われ方は?

本題

★スレッドってなに?

スレッドについていろいろな記事が検索できるので、それを参考にするべきですが、
一言でいうと?という観点でしっくりくるものが見当たらない。
ということで、ここではスレッドは、仮想的なCPUと定義しておこうと思います。
スレッド自体は、複数個同時に存在します。
参考までに自分の端末では、ある瞬間に存在するスレッドの数は1976でした。
f:id:kinakomotitti:20180412220850p:plain
簡単のためにCPUが1つのPCについて考えます。
1つのCPUだけあるPCにおいて、ある瞬間に実行されているスレッドは1つです。
しかし、常に1つの同じスレッドだけが実行されているわけではないです。
(1つのスレッドだけが動くのであれば、ほかのアプリが完全に沈黙していることになります。
また、その1つのスレッドが無限ループに入ったとき、PCが操作不能になってしまいます。)
実際は、実行するスレッドを細かく切り替えることで動いていきます。
「1つのCPUが実行するスレッドを細かく切り替える→実行できる処理がたくさんあるように見える。」
ということから転じて、スレッドは、仮想的なCPUとしておこうと思います。

★どんな時に使う?

わかりやすい説明があった記事を参考に乗せておきます。
technet.microsoft.com

アプリケーション開発において、マルチスレッドにするべきシナリオは大きく2つあると思います。

  • 画面が固まらないようにする。

あるGUIアプリで、ボタンを押したけど、反応がない。ただの屍のようだ・・・
と思って、ほかのボタンを押してみたらアプリが白くなった。
ということってよくあると思います。
そういう場面を何とかしたいときに、ボタン押下で実行される「重たい処理」を画面を実行しているスレッドとは別のスレッドで実行して解決するシナリオです。

  • 大量の計算処理を効率よく行う。

実際に出会ったことがないのですが、並列処理をすると計算処理を短縮することができます。
1~1000までを足し算する処理を2つのスレッドでそれぞれ500ずつ分担して実行すれば、(おそらく)1つのスレッドで実行するより半分程度の時間で処理を完了することができます。
そういうイメージのシナリオです。

★使うときの注意点は?

スレッドを使うときの注意点は、まずスレッドセーフな処理であることがあげられます。
スレッドセーフについてはまた別でまとめたいと思います。
ここでは、スレッドセーフとは
複数のスレッドが同時に動作し、データの不整合を生じさせないもの
であるということでお茶を濁したいと思いますw

次の注意点はスレッド作成にかかるコストについて意識することです。
スレッドはとても便利で、設計によっては処理時間を大幅に短縮することができたり、
GUIアプリケーションの使い勝手を向上させることができます。
しかし、それらスレッド自体を作成するコスト(オーバーヘッド)も知っておくべきです。
すべてのスレッドには、スレッドコンテキストと呼ばれるデータ構造体があります。
スレッドコンテキスト構造体は、前述の「実行されるスレッドを細かく切り替える」処理で実行中のスレッドが切り替わるとき、最後に実行された状態を保持するために利用されます。
この構造体を持つこと自体が、メモリを消費します。
また、「細かく切り替える」処理はコンテキストスイッチと呼ばれる処理です。
切り替える前に状態を保存し、次に切り替えるスレッドを探すなどの処理が実行されるため、その処理自体に時間が消費されます。
また実行コンテキスト構造体と呼ばれるものもあります。
この構造体には、セキュリティ設定、論理コンテキストデータ、ホスト設定の情報が格納されます。
これらの情報についてもメモリを消費して管理することとなります。

これらのオーバーヘッドはスレッドを使い、問題を解決するためのトレードオフになります。
払うべきところは払って、無駄に払わないようにしないといけないです。

★実際の使われ方は?

感動する例があったので一部メモしておこうと思います。
それは、Visual Studioの「ビルド」です。
いつもこの手のお話でよい題材がないなぁと悩んでいましたが、これならしっくりきました。
ビルド実行中でも、Visual StudioGUIは操作が可能ですよね!
ほかにも、コードエディタでコードを編集するときに実行される自動コンパイルもよい例だと思います。

まとめ

スレッドは仮想的なCPU。
スレッドを効果的に使うことで、処理時間の短縮や、使いやすいGUIを開発できる。
スレッドには作成に時間的・メモリ的なオーバーヘッドがかかるので、無駄遣いはダメ、絶対。

C# × ベンチマーク × パフォーマンス解析するためのツールをさがしてみた

この記事の目的

この記事では、
今後使っていくベンチマークツールを決めること
を目的としています。

アジェンダ

  1. ベンチマークツールの選定
  2. System.Diagnostics.PerformanceCounter
  3. Benchmark DotNet
  4. BenchShark

本題

ベンチマークツールの選定

非同期処理のことを調べていると、こう実装すると「パフォーマンスが良い(or悪い)」という言葉をよく目にすることがあります。
そしてその中の大半の記事では、具体的にどの程度のパフォーマンスの違いがあるかについて言及しません。

それではわからない( ゚Д゚)


じゃあ、自分で調べてみたらいいじゃん(/・ω・)/


System.Diagnostics.Stopwatchクラス使ってパフォーマンスを・・・
と思っていたのですが、これだと、処理時間だけしかわからないです。
かといって、ほかにパフォーマンスを計測する手段がない。

そんなこんなで、Nugetでパフォーマンス解析(ベンチマーク)をするためのライブラリを検索してみました。

まずは「パフォーマンス」で検索
f:id:kinakomotitti:20180401231415p:plain

・・・まぁないよね。
次に「ベンチマーク」で検索
f:id:kinakomotitti:20180401231446p:plain


・・・ない。どんどん行きます。
f:id:kinakomotitti:20180401231458p:plain

Microsoftが出しているそれっぽい名前のものがあった!
とりあえず、キープということで・・・
最後は「Benchmark」で検索
f:id:kinakomotitti:20180401231544p:plain

思いのほか、いっぱいあった(*´Д`)
いっぱいあってわからないので、名前が気になるもの2つを候補としました。
・Benchmark DotNet
・BenchShark

★System.Diagnostics.PerformanceCounter

概要:Windowsのパフォーマンスカウンターにアクセスする機能を提供するクラスです。
パフォーマンスモニターの値を使った処理を実装する際に使うクラスの様です。
これはこれで気になりますが、今回の目的のブツではないようです。

PerformanceCounter クラス (System.Diagnostics)

★Benchmark DotNet

概要:ベンチマークのための強力な.NETライブラリ
公開日:2018年3月2日 (2018/03/02)
Home - BenchmarkDotNet Documentation

実際にやってみた手順を残しておきます
Step0)コンソールアプリを作成
Step1)Nugetでライブラリを取得
Step2)サンプルプログラム実装

	    [HtmlExporter]
	    public class Log4netTester ←パフォーマンス計測対象クラス
	    {
	        private static ILog logger = LogManager.GetLogger("kinakomotitti");
	
	        [Benchmark]
	        public void Test01() ←パフォーマンス計測対象メソッド
	        {
	            logger.Debug("Test");
	        }
	
	        [Benchmark]
	        public void Test02() ←パフォーマンス計測対象メソッド
	        {
	            //no process
	        }
	    }
	    public class Program
	    {
	        public static void Main(string[] args)
	        {
	   //計測処理
	            var summary = BenchmarkRunner.Run<Log4netTester>();
	        }
	    }
	


Step3)Releaseビルドの作成 ※デバッグビルドでは結果が計測されません
Step4)実行
Step5)結果の確認
Releaseビルドの実行ディレクトリに結果ディレクトリが自動で作成されます。
f:id:kinakomotitti:20180402221126p:plain
カタツムリでは、いろいろな出力形式を提供してくれています。
今回は、HTML形式で出してみました。
f:id:kinakomotitti:20180402221133p:plain
パソコンのスペックまで出してくれるあたり便利ですねw
計測も複数回にわたって処理を実行し、その平均を求めてくれるました。
Stopwatchつかって一回実行して「パフォーマンスガー」って言ってた自分が恥ずかしいです。。。

もう、パフォーマンス計測は一生これを使っていこうとすら思うくらいのツールだと思いました。

★BenchShark

概要:.NETアプリケーションのベンチマークパフォーマンスのための軽量ライブラリ。 BenchSharkは、コード内のボトルネックを追跡するために、機能の速度を評価するための強力で使いやすいAPIを提供します。
公開日:2013年11月19日 (2013/11/19)
wiresharkとにた名前だったので、ピックアップしてみました。
5年前にリリースされたものだったのですね。
こちらも使い方の簡単メモを残してみます。
Step0)コンソールアプリケーションを作成する
Step1)NugetでBenchSharkをインストールする
Step2)計測コードを実装する(カタツムリサンプルに追記しました。)

	    [HtmlExporter]
	    public class Log4netTester
	    {
	        private static ILog logger = LogManager.GetLogger("kinakomotitti");
	
	        [Benchmark]
	        public void Test01()
	        {
	            logger.Debug("Test");
	        }
	
	        [Benchmark]
	        public void Test02()
	        {
	            //no process
	        }
	    }
	    public class Program
	    {
	        public static void Main(string[] args)
	        {
	            //KataTsumuri
	            //var summary = BenchmarkRunner.Run<Log4netTester>();
	            var tester = new Log4netTester();
	            var shark = new BenchShark();
	            // Evaluate the function with 100 iterations
	            var result = shark.EvaluateTask(tester.Test01, 1000);
	            Console.WriteLine("Total elapsed: {0} milliseconds / {1} ticks", result.TotalExecutionTime, result.TotalElapsedTicks);
	            Console.WriteLine("Average elapsed: {0} milliseconds / {1} ticks", result.AverageExecutionTime, result.AverageElapsedTicks);
	             result = shark.EvaluateTask(tester.Test01, 1000);
	            Console.WriteLine("Total elapsed: {0} milliseconds / {1} ticks", result.TotalExecutionTime, result.TotalElapsedTicks);
	            Console.WriteLine("Average elapsed: {0} milliseconds / {1} ticks", result.AverageExecutionTime, result.AverageElapsedTicks);
	            Console.ReadKey();
	        }
	    }

Step3)実行&計測結果確認
f:id:kinakomotitti:20180402221150p:plain
サメツールでは、Action型の引数と、イテレーションを引数で指定して実行することができます。
メソッドやクラスに属性を付与せずに簡単に計測を開始できるのが素敵だと思いました。
結果も自分の好きなフォーマットで出力できるので、オリジナルライブラリにラップするのも簡単にできそうです。

まとめ

今回はベンチマークツールとして、Benchmark DotNetBenchSharkの2つの概要をざっくり見てみました。
どちらも使い勝手が良くて素敵だと思います。
どちらも使っていきたいですが、今後はBenchmark DotNetを使っていこうと思います。
(公開日、出力ファイル形式、を考慮しました。)
本格的に使い始める前に、もう少し使い方を研究していこうと思います。

バックグラウンドスレッド × フォアグラウンドスレッド× 違いをたしかめてみた

この記事の目的

この記事では、
2種類のスレッドの違いについての動作の違いをまとめること
を目的としています。

本題

  1. スレッドの種類
  2. バックグラウンドスレッド
  3. フォアグラウンドスレッド
スレッドの種類

CLRで提供されているスレッドには、フォアグラウンドで実行されるものと、バックグラウンドで実行されるスレッドの2種類があります。
フォアグラウンドスレッドは、呼び出し元のスレッドが終了しても生き残ります。
そのため、ユーザー目線だと、ウィンドウを閉じたのにアプリが終了しない・・・
という状況が発生するものです。
逆に、バックグラウンドスレッドは、呼び出し元のスレッドが終了すると、強制的に処理が終了させられます。
そのため、ユーザーが意図したとおり、ウィンドウをすぐに閉じることができます。
途中になった処理をどうフォローするかは別の問題ですが・・・

どっちがより良いかについては、ケースバイケースだと思います。

が、

ユーザー「プロセスを終了したいと思い操作した。」

ということを考えると、ユーザーの思った通りに動作するバックグラウンドスレッドを優先して利用するべきだと思います。

バックグラウンドスレッド実験

以下のサンプルコードを実行して動作を確認してみます。

    static class Foreground_BackGround
    {
        public static void Main()
        {
            Thread thread = new Thread(Worker);
//バックグラウンドで動くように指定
            thread.IsBackground = true;
            thread.Start();
        }
        private static void Worker()
        {
            System.Threading.Thread.Sleep(10000);
        }
    }

実行すると、Main処理が終了すると同時にコンソール画面が閉じます。
これは、Workerの処理が実行中ですが、呼び出し元のスレッドが終了したため、
バックグラウンドスレッドも終了させられたことによります。

フォアグラウンドスレッド実験

同様のコードをフォアグラウンドように変更します。

    static class Foreground_BackGround
    {
        public static void Main()
        {
            Thread thread = new Thread(Worker);
//フォアグラウンドで動くように指定
            thread.IsBackground = false;
            thread.Start();
        }
        private static void Worker()
        {
            System.Threading.Thread.Sleep(10000);
        }
    }

実行すると、Main処理が終了してもコンソールが閉じることなく画面上にとどまります。
Workerが処理しているためです。(10秒間Sleepしています)
なお、Thread.IsBackgroundの規定はfalseです。
そのため何も設定しないと、フォアグラウンドスレッドとして処理が実行されます。

まとめ

しぶとく強く・・・フォアグラウンドスレッド
サバサバ  ・・・バックグラウンドスレッド