コマンドラインプログラムで非同期処理ってどう書くの?

awaitableconsoleprogram

… ネタが降ってきた (;´Д`)

.NETのコンソールプログラムは、Visual Studioで普通に作ると、以下のようなテンプレコードが生成されます。

namespace ConsoleApplication2
{
	internal static class Program
	{
		public static int Main(string[] args)
		{
			return 0;
		}
	}
}

勉強会のasync/awaitシリーズで説明したシチュエーションは、WPFやWinFormsという環境での話でした。そこでは、「UIキュー」が重要で、このキューに非同期処理の完了が放り込まれ、メインスレッドがこれを拾い上げて処理する事で、await以降の処理が実行されることを説明しました。

コンソールで実行されるコードの場合、この「UIキュー」が存在しません(WPFやWinFormsのインフラを使った場合は生成されますが、ここでは扱いません)。そのため、await時に「ハードウェイト」しても困らない事になります。

UIキューが存在する環境でハードウェイトすると、UIキュー内のエントリが実行されなくなります。目に見える問題として、ユーザーの操作(ウインドウを移動したりサイズ変更したり、ユーザーインターフェイス要素の操作)が無視され、アプリケーションが固まっているように見えます。

しかし、コンソールアプリケーション実行時のウインドウ「コマンドプロンプト」は、アプリケーションのスレッドの状態に関わらず、常に操作可能です。以下のProcessExplorerのスクリーンショットは、コマンドプロンプトウインドウを激しく動かしている時に撮ったものです。

awaitableconsoleprogram3

コンソールアプリケーション(ここではcmd.exe)を起動すると、同時に子プロセスとして「conhost.exe」が起動します。はっきりしたことは分かりませんが、上記のようにウインドウの操作を行うと、このconhost.exeの負荷が上昇する事から、ウインドウメッセージの処理はこのプロセスが受け持っている事が推測できます。そうであれば、実際のコンソールアプリケーションは、UIキューの処理に影響される事無く(元々持っていない)、そしてユーザーインターフェイスがブロックされる事が無く、動作するのです。

話を戻して、コンソールアプリケーションではUIキューを持っていないので、スレッドがハードブロックしても問題ありません。Taskクラスを返却する「非同期メソッド」は、必要な個所でハードブロック出来ます。この事を利用して、以下のようなスケルトンコードを考える事が出来ます。

namespace ConsoleApplication2
{
	internal static class Program
	{
		private static async Task<int> InternalMainAsync(string[] args)
		{
			// あんな非同期やこんな非同期処理 ...

			// Console.WriteLineへのアクセスはスレッドコンテキスト違反にはならない
			Console.WriteLine("async/await on Console Application.");
		}

		public static int Main(string[] args)
		{
			try
			{
				return InternalMainAsync(args).Result;
			}
			catch (Exception ex)
			{
				Console.Error.WriteLine(ex.ToString());
				return Marshal.GetHRForException(ex);
			}
		}
	}
}

Mainの最初の処理として、InternalMainAsyncメソッドを呼び出します。このメソッドはTaskクラスを返却する非同期メソッドです。そのため、このまま放置すると次の処理に行ってしまいます(Mainを抜けて終了してしまう)。そのため、Waitを呼び出してハードブロックする必要があります。上記の例ではResultプロパティを呼ぶことで、間接的にハードブロックしています(戻り値intを取得するため)。

一方、InternalMainAsyncの中の処理は全て非同期で記述できます。ここでの知識は、WPFやWinFormsで非同期処理を記述する時と全く同じ知識を活用できます。言い換えると、普段から非同期処理を書いているなら、同じ流れで書いて問題ないという事です。

スレッドはどうなるのか? ですが、メインスレッドとUIキューの関係は無く、メインスレッドはResultでハードブロックしているので、全ての非同期処理(非同期処理の継続操作)はワーカースレッドのコンテキストで駆動されます。

今話題にしているのはコンソールアプリケーションでしたね? 例えば、ワーカースレッドからConsole.WriteLineを呼び出しても問題なく出力出来ますね? 勿論、マルチスレッドアクセスが認められないクラスやメソッド、特定のスレッドコンテキストに紐づくクラス等を扱う場合は、スレッド同期やマーシャリング等の操作が必要になりますが、この辺の知識はTask.RunやThreadクラスを使って手動でワーカースレッドを作った時と同じように考えればOKです。

追記: 現代の話 (2020年)

ネタとしてはもうかなり前から出来るようになっていますが、C# 7.1以上を使用している場合は、以下のように直接MainメソッドがTaskを返すように書く事が出来ます:

namespace ConsoleApplication3
{
	internal static class Program
	{
		public static async Task<int> Main(string[] args)
		{
			// あんな非同期やこんな非同期処理 ...
		}
	}
}

ポイントは、

  • メソッド名はMainであること
  • 引数は従来通り、無しかstring[]であること
  • 戻り値の型がvoidの場合は従来通りの扱い、Task又はTask<int>の場合のみ、Mainを非同期メソッドとして認識

.NET Core/Frameworkのバージョンではなく、C#のバージョンによって使用可能になります。つまり、この機能は、コンパイラが判断して適切なコードを自動生成する事で実現しています。生成されるコードは、私たちが手動で行っていたのと同じように、Wait()やResultを呼び出してハードウェイトしている事になるため、UIキューを使うようなシチュエーションでは使えません。

プロ生ちゃんをひろっちゃう! – プログラミング生放送勉強会 第30回@名古屋ソフトウェアセンター

プログラミング生放送勉強会で「プロ生ちゃんをひろっちゃう!」というタイトルでセッションに登壇してきました。

WP_20141108_12_21_12_Pro

初めての参加で、まったりと聞こうと思っていたのに、何故か登壇席にいた… そういうセッションです (;´Д`) 一体どういうことなのか、良く分からない…

仕方が無いので、プロ生ちゃんベースに、いつもとは違う方向性でセッションしました。途中、スライドが見えづらいというリアルタイムなツッコミに動揺し、しかもデモしようとしたら、Azureのネットワーク障害で見せられないという、デモ失敗あるあるでガタガタな結果に orz

すいませんすいませんすいません(泣

精進出来るようにがんばります。

内容はざっくり、プロ生ちゃんサイトの壁紙ページをスクレイピングして、非同期で画像をダウンロードしながらWPFでデータバインディングして表示するという内容です。

スクレイピングするために、どうやってサイトのHTMLを調査するか、そして実際にスクレイピングする時に使えるライブラリや、HTMLの解析方法、ユーザーインターフェイスをスムーズにする為の非同期処理の概要をちりばめました。

以下にスライドを置いておきます。また、例によってソースコードはGitHubに上げてあるので、見る事が出来なかった方は参考にして下さい。

スライド: プロ生ちゃんをひろっちゃう!.pptx
ソースコード: GitHub kekyo/Pronama.ScrapingViewer

メタプログラミングでEXCEL仕様書よ、さらば! – 第一回 Center CLR勉強会

BlogImage

新しいコミュニティ「Center CLR」を立ち上げました。今回はその第一弾となる勉強会で、登壇してきました!
当日は、生憎の雨模様でしたが、エントリーいただいた全ての方が出席いただいて感謝しています。

centerclr-p1

この勉強会は、中部圏での.NET Framework中核技術であるCLRをネタに展開して行こうと思っています。一応セッション形式の進行ですが、セミナーではなく勉強会なので、随時質問やところどころの脱線など、Welcomeでやっていく予定です。初めての方もお気軽にどうぞ!

centerclr-p4

次回勉強会の開催はまだ未定ですが、ご興味ある方は、Center CLR公式サイト(Facebookページ)や、DoorKeeperをチェックしてみて下さい。また、私のtwitterや公式twitterアカウント「@centerclr」でもつぶやきます。


さて、私のセッションは、「メタプログラミングでEXCEL仕様書よ、さらば!」という題目で、仕様書に対してEXCELを使用することの是非と、CLRで何が改善できるのか?という事をテーマに解説しました。出席者からもいろいろな質問を上げて頂き、良い勉強会になったかなと思います。

普段、あまりなじみが無いと思われる技術を掘り下げたため、セッション時間が2時間越えとなってしまいましたが、どうにか形になってほっとしています。

解説中のサンプルコードは、私のGitHubから参照可能です(セッション中に発見したコメントは、このブログ掲載時にはまだ修正していませんが、すぐに修正します)。また、セッションのプレゼンは、以下に置いておきます。

メタプログラミングでEXCEL仕様書よさらば10.pptx

それでは、また!

「async/await ダークサイド is 何」 – 第10回まどべんよっかいち

「async/await ダークサイド is 何」というお題で、登壇しました。
第10回まどべんよっかいち

このセッションは、前回の「いまさら恥ずかしくてasyncをawaitした – 第9回まどべんよっかいち」や、「これからの「async/await」の話をしよう – 名古屋GeekBar」の続きで、前回話しきれなかった、よりエンハンスした内容となっています。

ちょっと巻きましたが、非同期処理のエッセンスを伝える事が出来たかなと思います。
プレゼンは以下に置いておきます。

async-awaitダークサイドis何

ご清聴ありがとうございました。多分、GeekBarでも再編集版をやると思いますので、今回参加できなかった方は、次回是非参加してください!
それでは。

趣味のAzure Websitesでパケ死必定?!・自腹課金の現実 – JAZUG名古屋@3碧目 ~ツナガレJAZUG 4周年!~

「趣味のAzure Websitesでパケ死必定?!・自腹課金の現実」というお題で登壇してきました。

イベントはこちら:DoorKeeper: JAZUG名古屋@3碧目 ~ツナガレJAZUG 4周年!~

先日のWebSitesへのブログ移行(つまり、今見ているこのブログ)のお話です。

プレゼンはこちら:趣味のAzure Websitesでパケ死必定?!_2.pptx

ご清聴ありがとうございました。またよろしくお願いします m(_ _)m

継承とインターフェイス

おはようございます。毎度質問ばかりで申し訳ないのですが。以前後輩に、継承はインターフェースみたいな使い方もできるけどどう使い分ければいいですか?って質問された時にうまく答えられなくて。上で言ってる使い方っていうのは親のクラスやインターフェースを引数に持って子のクラスや実装クラスを渡すみたいな使い方です。僕は上のような書き方はどちらでも書けるけど継承はそういう使い方がそもそも目的ではなく、同じような処理や構造を使い回すために利用するのかなと思っていて、そういう考えで使うならインターフェースを使うべきなのかなと思っていたのですが、まったく自信がなくて答えられなくて、今度コンタクトとれたら教えて頂きたいと思ってました。構文的な違いは一応調べてみて、差異はいろいろあったのですが、同じような使い方ができる時の使い分けの考え方について教えて頂きたいです。

…ネタが降ってきたw

物理的(言語的)な制約としては、その理解で良いと思います。C#をちょっと外れてC++の場合、C++にはインターフェイスという直接的な概念が無いのですが、純粋仮想関数(つまり、実装を持たない、表面的な構造だけを示したメソッド)の集合をクラスで表現した時、それがインターフェイスとなります。つまるところ、普通のクラスのメソッド群から「実装」を取り除き、表面的な見た目(メソッドシグネチャ)だけにしたものが、インターフェイスです。

で、インターフェイスとクラス継承の違いですが:

  • クラスの場合は、基底クラスの実装(振る舞い)を「継承」して、新たな振る舞いを付け加えたり、差し替えたりする事が出来る。
  • インターフェイスの場合は、表面的な見た目だけを定義し、実際に使う側からはその「見た目」が同一に見えるように強制出来る。

ぶっちゃけ、よく使う説明は:

仮面ライダーのお面がインターフェイスだと思いねぇ(ライダーマンが良いかも)。お面を誰がかぶっても、はた目にはライダーにしか見えない。ライダーに見せかける事によって、ショッカー軍団が襲ってくる(機能)。ライダーのお面をかぶらないタダの人間は、ショッカーの敵に適合しないので襲われない(本当か?)

「中の人」が誰であれ、お面をかぶると「仮面ライダー機能」に適合する。誰であれ、というのが、「どんな実装のクラスでも」と言い換えられます。極端な話、ゴリラがかぶっても良い。

しかし、基底クラスを継承する場合は、少なくともかぶる人が類似性(具象クラス)を持っている必要があります。中の人は少なくとも人間でなければならず、しかも改造人間でなければならないという制約が生じます。

更に、ウルトラマンのお面をかぶることも出来ます。それも同時に。ウルトラマンのお面に反応する敵は、仮面ライダーのそれとは異なります。違いは、顔の作り、「メソッドシグネチャの異なるメソッドの集合」という事になります。これを同時にかぶった人間は、フィクションでも実在しませんが、ある時はライダーに変身し、ある時はウルトラマンになる、というような、「仮面ライダーvsウルトラマン」的なネタがOKって事です。

#ちょっと嘘があります。お面を動的に切り替えれる訳ではありません。コンパイル時には決定されている必要があります。

もし、どちらで実装すべきか悩む場合は、インターフェイスを使用する前提にしておく事をお勧めします。その方が自由度が高い為です。多くのメソッドをそのまま派生クラスで流用したい場合に、基底クラスを使用したくなりますが、そもそもそんなに沢山のメソッドが単一のクラス内に定義されていることが問題です。

身近な例ではWPFやWindows Formsのクラス群が思い浮かびますが、あの実装は様々なトレードオフの検討の上で、あのような構造になっている、特殊な例です。

また、インターフェイスで分離を行う事で、副次的な良い効果があります。一つは、実装を明確に分離できる事です。基底クラスの実装に依存していると、派生クラスの実装がどのように基底クラスに依存しているのかを理解することが難しくなります(基底クラスと派生クラスの高度な分離は、オブジェクト指向版gotoだと言う記述をどこかで見た気がしますが、その通り)。インターフェイスで実装を分離していると、別のクラスに実装が分離されるので、正しくカプセル化を施していれば、機能の境界線ははっきりします。

もう一つは、自動化ユニットテストを記述しやすくなる事です。ユニットテストを記述する場合は、ファイルやネットワークやデータベースなどの「外部リソース」を、テストから分離しておかないと、テスト結果が不安定になります(テスト開始時には常にイコールコンディションとなるようにしないと、テスト結果がまちまちになってしまうが、ファイルやデータベースの事前準備を自動化するのは面倒)。

インターフェイスで分離されていることで、これらの外部リソースアクセスを、全く独自の、実際と異なる、しかしながら表面的には同一に見える実装に差し替えてテストすることが出来ます。インターフェイスのお面をかぶる「中の人」が誰でも良い、という特性を簡単に生かす事が出来ます。もし基底クラスを使用すると、基底クラスの機能に縛られ、全く異なる独自実装に置き換えることが難しいかもしれません。

C#の場合、メソッドはデフォルトで非仮想関数です。そのため、オーバーライドは出来ません(newを使用すると、名前が同じでも異なるメソッドとして扱われる)。インターフェイスであれば、最悪はラッパークラス(右から左にメソッド呼び出しを転送)を実装すれば、回避出来ます。

複数のインターフェイスを実装する場合に、たまたまメソッドシグネチャが同一であっても実装を分けたい場合には、インターフェイスの明示実装という手法を使うことで実現出来ます。

なお、CLRに限って言えば、仮想関数の呼び出しよりもインターフェイスメソッドの呼び出しの方がコストが高かったと思います。勿論、アプリケーション全体を通して、インターフェイスメソッドの呼び出しのコストがどの程度の割り合いなのかを評価しなければ、一概に悪いとは言えません。むしろ、その問題だけを引き合いに出してインターフェイスによる分離を行わないのは、本末転倒でしょう(そして、改善するなら測定してからにしましょう)。

#で、この項のネタは、先日見てきた「これ」に引っ張られてたりするw
#キャラクターネタにすると、諸般の事情で絵が描けないのが後の祭りだった…

これからの「async/await」の話をしよう – 名古屋GeekBar

「これからの「async/await」の話をしよう」なんて、大それたタイトルで登壇してきました (´Д`)

前回のまどべんよっかいち版に加筆・修正したものですが、時間に自由度があったので、細かく解説させてもらいました。
平日夜という事で、参加された方、長時間のご清聴ありがとうございました。

本編で紹介しましたが、この内容は〆られていないので、続編をやろうと思っています(次回まどべんよっかいちでの登壇になると思います)。ぜひ、ご参加下さい。

プレゼンはこちら:これからの「async-await」の話をしよう.pptx

あと、即興でLTして頂いたせがゆうさんのプレゼンを、代理でリンク張っておきます。せがゆうさん、お疲れ様でした。またよろしく!

それでは、また。

WordPress on Microsoft Azureの料金

wpazure6

フフフ、ネタが降ってきた (;´Д`)

とは言っても、まだ始めたばかりですが、参考にどうぞ。

wpazure7

ちょっと補足すると、トラフィック5GB(送信)までは、課金されません。まだまだ0.15GBですね。それとは別にコンピューティング課金が行われていて、これは「共有」なので従量課金ですが、単純に使用時間で積算されるので、208時間・276円という事です。そして、ここには表示されていませんが、ClearDBは無料の20MB枠なので0円。つまり、これが使用7日目での実績ですね。但し、WordPress.comからトラフィックを転送したのは21日からなので、今後どうなるかな?

トラフィックが予測可能なら、非常に使いやすい便利な計算機があります。

wpazure8

WordPress on Microsoft Azure

というわけで、wordpress.comでホスティングしていたブログを、Microsoft Azure WebSitesに引っ越しました。合わせて、保有しているドメイン名で引けるようにしました。
同じような事を考えている方は参考にどうぞ。

カスタムドメインの導入は完全無料ではありません

カスタムドメインをWebSitesに導入するには、「共有」プラン以上にする必要があります。Azureの有料プランは従量課金であるため、趣味のサイトをAzureでホストすることに抵抗があるかもしれません。もっとも、大してPVが伸びないことが分かっているのであれば、定額ホスティングとさして違いは無いように思います。この辺りは、痛い事があれば別のホスティングに移せばいいや的に、楽観視しています。

カスタムドメインの導入は簡単

やることは2つだけ。一つは自分が所有するDNSサーバーのレコードに、CNAMEで「kekyo.azurewebsites.com」のようなWebSitesへの標準FQDNを追加します。もう一つは、Azureの管理ポータルから「カスタムドメインを管理する」で、ドメインを追加します。
wpazure2
wpazure1

トラブル発生

実は、今回の引っ越しはもっと前に計画していたのですが、Azure上でWebSitesが追加できないというトラブルに見舞われて、遅れていました。大分以前から「kekyo.azurewebsites.com」で何度か構築・破棄のテストを行っていたのですが、どうもその時にAzureデータセンター側で何か問題が発生していたようで、今回の移行の際にこの名前でWebSitesが生成出来なくなってしまいました。

新規に生成しようとすると「プロビジョニングに失敗しました」というエラーが発生して、生成できないというものです。

wpazure3

このエラー、検索すると若干ですが事例があり、「しばらくしたら直った」的な、どうにも煮え切らない回答が。

何しろ、まだ何か行う前段階であり、このアカウントで他のサービスも使っておらず、エラーメッセージもこれだけでトラブルシュートも出来ず、「何をどうすりゃいいんだ?」という状態で困ってしまいました。
仕方が無いので、サポートを依頼しようとするものの、無料枠インシデントの要因にはこのような問題を直接指定するものがなく、何となく暗雲立ち込めつつも、サブスクリプションに対する問い合わせでやってみました。

が、技術的な内容の問い合わせは、有料インシデントとなるという回答… うーん、まだ使用も始まってなく、こちらに落ち度があるとは思えないのですが。もやもやしましたが、Azureでホストするというのは決めた事なので、サポート契約を行いました。

サポート契約と聞いて、仕事でもないので「もう駄目ぽ」と思ったのですが、念のため料金を確認すると「三千円(3,194)」ということで、「あれ?一桁間違っていないか?」と見直すと、更に「一か月間」とあります。これ、従来のテクニカルサポートインシデントと比べると「激安」じゃないのか?!

仮に一回三千円でも、個人では抵抗が大きいかもしれない(「これにて、以上!」とか言われて終了したらガクブルかもw 実際にはそんな事は無いんですが)けど、一か月間何度でもOKとなれば、これはかなり抵抗感が薄いと思います。加えて、MSの有償サポートはとても良い範囲に入ると思います。

と言う事で、調査すること一週間で、どうもデータセンター側のデータに古い情報が残っていて、これが原因でエラーが発生していたとの事(あるあるだ…そして予想通り)。この情報を手動削除するよりも、現在展開中の新しいポータルサイト(プレビュー)からWebSitesを生成すると回避可能との連絡が。プレビューサイトの見た目は洗練されているけど、何をどう操作すれば良いのかいまいち分かりにくいため、まだあまり使っていませんでした。

早速プレビュー版のポータルサイトからWebSitesを作成したところ、今度は問題なく生成完了!やっと先に進むことが出来ました。生成が確認出来たので、インシデントはクローズ。一応担当の方は、MS本社にも問題(これは有償案件なのか?)を掛け合って頂いたそうですが、どうしても覆せなかったこと、改善すべき事として検討しますとの回答だったので、今後に期待する事にしました(確約して頂いた訳ではないので、この件でゴリ押しはしないで下さい)。

WordPress日本語版がテンプレートから簡単に生成出来る

wpazure6
Azure WebSitesの生成時に、「WordPress日本語パッケージ」というテンプレートを使う事ができます。これを指定して、SALTキー文字列を適当に入力するだけで、あっという間にWordPressサイトが生成出来ます。zipで持ってきて展開してFTPでアップロードして云々とか面倒な作業は不要です。
もちろん、独自にコードをいじりたい場合は、FTP/SFTPで接続して直接編集する事も出来ます。

Azure特有のポイント

まず、データベースは「ClearDB」という、サードパーティのMySQL PaaSを使います。無料枠で作る場合は、こちらのサービスも無料枠で20MBを1DBだけ割り当てる事が出来ます(Azure WebSitesが有料枠でも、ClearDB無料枠と組み合わせ可能です)。但し、WebSitesをホストする同じ地域で割り当てないと、地域間通信に課金されてしまいます(確かテンプレートで生成した場合は、自動的に同じ地域になった気がします)。

20MBというのは、ディスク容量に比べると極端に小さいのですが、画像ファイルなどはディスクに格納されてDBには入らないので、すぐに埋まるという事も無いでしょう。

ClearDBへの接続についてもポイントがあります。少し前にリツイートしたのですが、ClearDBへの接続回数が多いと、スロットリングを受けてしまうようです。WordPressの現在の実装(3.9.2)は、MySQLへの接続が非プールらしく、これを改造しないと制限に引っかかってしまいます。

で、ソースコードを手で変更するのも面倒(自動アップデートされると元に戻ってしまう)事もあり、Azure WebJobというジョブ機能で定期的に修正を試みるのを推奨していたのですが、やり方は書いてないw

WebJobについて調べ始めると、これはこれでシンプルで面白い機能だと思ったのですが、ここで「そもそもAzureでWordPressのホストは珍しいわけでもないんだから、WordPressのプラグイン無いだろうか?」と思って検索するとありました!

wpazure4

「Persistent database connection updater」です。しかもMSOT謹製でした。そうだよねぇ。

もう一つの問題は、AzureはSMTPのホスティングをやって無いって事です。これは仕方が無いので、外部のSMTPサーバーに任せます。私はoutlook.comのSMTPに投げさせるために、「WP-Mail-SMTP」というプラグインを使いました。SMTPサーバーを指定するだけです。これで、WordPressからメールを送信する場合でも行けます。

wpazure5

あと、出来れば通信による従量課金を減らしたいですね。WordPressに「JetPack」プラグインを導入すると、「Photon」というCDN機能が使えるようになります。これは、WordPress.comがCDNホストとなって、画像や動画を配信してくれるという嬉しい機能です。ぜひ有効化しておきましょう。

その他

Azureに絡む話はこのぐらいで、あとは単純な引っ越しの問題が残りました。投稿中のコードは、現在も無残な状態です。インポートプラグインが悪いのかもしれません(WordPress推奨なんですががが)。投稿数を考えると、手で直すかどうか迷う所。あとは、テーマの微調整かな。Twenty Fourteenは一見クールなんですが、余白あり過ぎで、テクニカルな記事にはあまりマッチしてない。画像の配置も違和感ありまくり orz
cssをいじって調整中です。

素人の Per-Monitor DPI

先日、開発用のデスクトップPCを新調しました。その際に、話題の4KモニターDell UP2414Qを追加しました。

dell-up2414q-overview1

T221と比較してDisplayPortで接続出来るので、母艦のインターフェイスに悩まなくても済みます(実際は悩んだんですが、それはまた別の機会に)。また、60Hz行けるのが良い点です。

で、これをUXGAのL200Pと縦に並べました。

PerMonitorDPI1

下がUP2414Q、上がL200Pです。ここからが面白い。
Internet Explorerを下から上にドラッグして移動します。

PerMonitorDPI2

2台のモニターは解像度が違い過ぎるため、ドラッグ中のウインドウがL200P側ではみ出てしまっています。また、解像度が低い分、IE上のテキストや画像も物理的に大きく表示されています。ただ、違和感はありません。元々解像度が違う事を分かっているので、大きくなってしまうことは予想出来ます。そして…

PerMonitorDPI3

L200P側に半分以上?移動すると、このようになります。一瞬、「えっ?」と思うのですが、いきなりIE内のコンテンツが縮小され、しかし、ウインドウの外郭のサイズは変わらないため、妙に縮まって見えます。

これは、「Per-Monitor DPI」というやつかな。どれどれ、実測してみるか。

PerMonitorDPI4

UP2414Q

PerMonitorDPI5

L200P

少しサイズが違いますが、おおむね同じサイズとなるように、ピクセルが縮小されているようです。サイズが違うのは、L200PからDPIが供給されていない可能性があると思います。

さて、コンテンツだけを注目すると、非常に良い機能です。が、この「コレジャナイ」的な違和感… ウインドウの外郭も縮小されたらパーフェクトだったかもしれません。

… いやいや、本当にそうだろうか?

ウインドウの外郭クロームは、ずっと固定的なピクセルサイズを基準に運用されてきたので、今更これが変わるのは微妙かもしれません(見れないので分かりませんが)。

ウインドウの外郭に違和感を感じるのなら、ストアアプリならどうかなと思い、テストしてみました。

PerMonitorDPI6

UP2414Q

PerMonitorDPI7

L200P

これは素晴らしい!同じアプリケーションでありながら、極端に異なる解像度のモニターでも、表面的な違いはほとんどありません。そして、4Kモニターであれば、細かい文字も美しく描画されています。

PerMonitorDPI9

UP2414Q

PerMonitorDPI8

L200P

もちろん、デスクトップアプリにおいても「最大化」して使用すれば、ストアアプリとほぼ同じ結果が得られます(Per-Monitor DPIに対応していれば、です)。

このような事もあり、両方のモニターを同じ目的で使うつもりだったのですが、L200P側ではストアアプリ(主にNeuroniaとFacebook)を動かしたままで配置し、4Kの方で通常の作業を行う、という使い方に落ち着きました。2画面(又はそれ以上)のモニターをどれも同じ目的で使おうと考えている場合は、やはり同じモニターで揃えたほうが良さそうですね。

なお、Per-Monitor DPIについては、以下の記事が参考になると思います。

4大(?)ブラウザーの High DPI 対応 (だるやなぎさん)
アプリの高DPI(High DPI)対応について 第1回 ~ 高DPIとは ~ (田中さん)