using record(まとめと復習)

書いた

github.com

自分の中での整理

個人的にrecordで一番良いと感じたのは、Primary ctorを定義した場合に、get; int; アクセサーと、値積み込み処理の生成を自動でやってくれる点。

今まで、C#

Constructorが動いたらobjectが利用可能になるように書きましょう

ってポリシーでやると、VS2019を使っていたとしても

  • 自動実装プロパティを定義する。
  • 自動実装プロパティをドラッグしてctrl + .を押して、ctorを生成する。

と、地味に面倒な作業が必要だった。

C#8まではinit set がなかったこともあって、Initializer経由で値セットするだけなのに、ついsetを書きがちな現象をよく見かけた(そして面倒な気持ちも理解できる。)

C#9でのrecordを使う場合、Primary ctorの定義を使っていけば、無用なset アクセサーは避けられる(そもそも自分で書かなくていい)し、コード書いてる側もわざわざctor書かなくても自動生成されるしで、丁度良いんじゃないかなあと今のところ思っている。

まだ、理解しきれているわけじゃないので、理解が進んだらまた書き直しor追記するかもしれない。

2021 モバイルPC沼

CES 2021も終わり、なんとなくモバイルPCの事情が見えてきた。

32GB ramモデルが増えてきた

昨年はXPS13や、Thinkpad x13等にしか選択肢がなかった32GBramの選択肢が、増えてきました。 このへんは、covid-19によるリモートワークが増加したことによる効果なのでしょうかね。

気になった端末たち

Surface Pro 7+

www.tanomail.com

Pro8 / Laptop 4が秋発売に延期されるということで、こちらの発売になったようです。

法人向けですが、個人事業主でも購入可能のようですね。

Elite Dragonfly G2

https://jp.ext.hp.com/notebooks/business/elite_dragonfly_g2/

こちらは残念ながら、国内向けは32GB ramがないようです。(2021/01/24 現在)

Thinkpad x1 Carbon gen9

https://www.lenovo.com/us/en/laptops/thinkpad/thinkpad-x1/X1-Carbon-G9/p/22TP2X1X1C9

こちらは軽量でありつつも、TigerLake Corei7 + 32GB ram + 16:10ディスプレイ+5Gということで、非常にパワフルな端末になりました。

キーボードもthinkpadなので問題なさそう。

ASUS ROG Flow X13 GV301

rog.asus.com

この端末、最大Ryzen 9 5980HS(ZEN3)を搭載しつつ、32GB ram + 16:10ディスプレイ + dGPU搭載(GeForce GTX 1650) + 62Whバッテリー というゲーミングやクリエイター用の技術仕様にも関わらず、w29.9 x D22.2 x H1.58 ~ 1.58 cm 1.3kg と非常に小さく、軽量です。 特にノート用HシリーズのCPU&dGPU搭載の13.4インチノートで1.3kgは驚異的に軽いですね。 Ryzen 9 5980HS(ZEN3)はIntel Core i9-10885H(CommetLake)よりも、シングルコア、マルチコアともに20%程度高速なのでCPUパワーは最高なのではないでしょうか。 非常に素晴らしいカタログスペックに見えますが、無理やりケチをつけるとすれば、

  • SSDのPCIeがgen3なので、そこまで高速ではない
  • storage自体の容量が1TBとこのグレードのPCとしては少し控えめ(昨今はフラグシップのノートPCだと2TBまで選択できることが多い。)
  • thunderbolt3 / 4が搭載されていない
  • WebCamが720P(Surfaceは1080Pを搭載)
  • マイクとスピーカーが少し弱そう

といったところがありますが、逆に言えばそれくらいです。 フットプリントもDが少々大きいですが、全体的にはスリム(A4用紙-297mm*210mmより少し大きい程度)ですし、持ち運べるクリエイターモデルと言ってよいのではないかと思います。 なお、外付けGPU Boxも発売するようです。

その他2021年に考慮すべきもの

TigerLake Hシリーズ(8C16T版のHシリーズTigerLake)は2021年下旬に出荷予定

=> XPS15とかの更新に影響が出るかも。

AlderLakeの出荷も2021年後半

=>Surface Pro8 / Laptop 4 の発売が見送られてるのはこの辺も理由の1つかもしれません。

今のところなんとなくのおすすめ

予算ある程度かけつつ、TigerLakeでいい場合

=> Thinkpad X1 Carbon gen9

dGPUやハイパワーなモバイルCPUを搭載した軽量Modelが欲しい場合

=> ROG Flow X13 GV301

Alder Lakeを待つ余裕がある場合

=> とりあえず2021/10以降の端末を待つ。(XPSやSuerfaceは載せてくるでしょうし、もしかしたらLifeBookも載せてくれるかもしれません。)

地味に大事なthunderbolt3/4、カメラやマイク

thunderbolt3/4はUSB3.2 gen2と比べて400%転送速度を持っているので、対応しているHubモニターを導入するときに、メリットがあります。 pc.watch.impress.co.jp

カメラやマイクは外付でもいいのですが、リモートワークが増えた昨今、ラップトップを移動して使うことも増えてくる(デスクやリビングのみならず、ラップトップをたまに職場にもっていったりする人もいるでしょうし。)ので、用途によっては評価ポイントに上げてもいい時代になってきましたね。

今年もモバイルPC沼は続いていく

今のところ、個人的にはASUS ROG Flow X13 GV301が気になっていますが、昨年Thinkpad X13で刻んだため、もう少し我慢できる状況なので、引き続きモバイルPCをチェックしていく日々が続きそうです。

C# インタラクティブの文字化けと向き合う

C# インタラクティブの文字化けを解消したいだけの人生だった

C#でREPLといえば、ここ数年はC#インタラクティブですが、16.8が来たタイミングで文字化けするマンになっています。 f:id:CreatioVitae:20210122003407p:plain

暫定対処法はあるけれど、正式対応については、これからRelease予定

developercommunity2.visualstudio.com

コントロールパネルから、システムロケールのオプションいじることで対処可能だけれど、VS2019としては修正を入れた上で、releaseする予定のよう。 2021/01/15時点では、Pending Release。

折角なので、暫定対処法について試す。

コントロールパネル↓↓↓

f:id:CreatioVitae:20210122004123p:plain

時計と地域↓↓↓

f:id:CreatioVitae:20210122004157p:plain

地域↓↓↓

f:id:CreatioVitae:20210122004237p:plain

管理-システムロケールの変更↓↓↓

f:id:CreatioVitae:20210122004338p:plain

ワールドワイド言語サポートで……のチェックをつけてOK。(OS再起動を要求されるので注意)

f:id:CreatioVitae:20210122004404p:plain

文字化けが治ったぞよ

f:id:CreatioVitae:20210122004618p:plain

対応自体は難しくないけれど、やや面倒

内容的にはVS2019のパッチで対応が入ってほしい内容なので、対応のreleaseを待ちます。

async / await Part1(まとめと復習)

using async / await Part1

TL;DR

非同期メソッド、実は必ずしも非同期じゃない。

=>1個目のawaitより手前まではただの同期実行。(並列実行は苦手なので、注意が必要。)

=>完了済みタスクをawaitしてもコストは低い。(コールバック展開しないから。)

async voidは使わない

=>無用なバグを積み込む原因になる。単体テスト実施時に検知できる可能性が100%にならないため、そもそも書いてはいけない。

=>戻り値取れない、例外受け取れない。言わばイベントハンドラのasync化のためだけに用意されたものなので、関わらないようにすること。async voidではなく、必ずasync taskを使う。

asyncメソッドの戻り値として受け取ったTaskはWaitしない。

=>デッドロックが発生する。使わないこと。

Constructorにはasyncがつけられない(非同期コンストラクターが欲しくても言語制約上作れない)

=>CreateAsyncメソッドを作成してその中で初期化処理を行う。(めんどくさい。でも出来ないからこうするしかない。)

async / await は I/O待ちの際に積極的に使う

async / await は I/O待ちの際に積極的に使うことでスレッドをロックされることを防ぎ、全体のスループットの向上が見込める。

今、自分自身の書いている処理自体はコールバック登録が行われることで若干のオーバーヘッドが積み込まれるが、I/O待ちの場合は、UIスレッドのアンロック+スレッドプールに移譲する処理も外部からのコールバック待ちに出来る。

I/O待ちの処理では積極的にasync / awaitを利用すべし。

非同期の種類

  • 同時実行(Concurrency)
  • 並列実行(parallelism)
  • I/O待ち(I/O Completion)

async / awaitの使いどころはI/O待ち

.NETの非同期処理機能(ここから先はasync / awaitを知る上での基礎的なお話も含む)

System.Threading.Thread;

  • 生スレッドを表すクラス
  • OS側の権限で切り替えを保証
  • 但し、 激重

    激重 is 何故

    スレッドが消費するリソース(1スレッド辺り)
  • スレッド自体の管理情報(1KB)
  • スタックメモリ(1MB)
スレッド開始&終了時のコスト
  • OSのイベント発火
スレッド切り替えに伴うコスト
  • OSの特権モードへの移行・復帰
  • レジスターの保存・復元
  • 次に実行するスレッドの決定
コード例
var t = new Thread(() =>{
    // 新しいスレッドで実行したい処理
});

t.start();

※ 勿論令和の時代に生スレッドをそのまま扱うことはありません。

System.Threading.ThreadPool;

  • スレッドプールを使うためのクラス

.NET 4以前はこちらを使う必要があった。 非同期処理の完了を待って違う非同期処理を開始することが出来ない。 例外や、処理結果の値を使うことが出来ない。

コード例

ThreadPool.QueueUserWorkItem(_ =>{
    // スレッドプール上で実行したい処理
});
//ここに何か書くと↑とは同時実行になる

スレッドプール Is 何

事前にいくつかスレッドを立てておいて、使いまわす仕組み スレッドに関わる負担を軽減する。 ただし、優先度や実行順番等の細かい保障はできない。

I/O待ちとスレッドプールの関係

非同期I/O APIを利用してI/O待ちを行う。 * Windows=> I/O完了ポート * Linux=>epoll(File I/Oはまた違うApiだった気もする。) * BSD/Mac=>kqueue I/Oが完了したらスレッドプールにコールバック処理を投函する仕組み。

System.Threading.Tasks.Task;

非同期処理の続きが書けるクラス 新規に非同期処理を開始するときはRunメソッドを利用する。 非同期処理のあとに何か続けたいときはContinueWithメソッドを利用する。 尚、ContinueWithを利用する際、何も指定しない場合は、後続タスクはスレッドプール上で実行される。 UIスレッドを操作したい場合は、TaskScheduler.FromCurrentSynchronizationContext()をTaskSchedulerの引数に設定すること。

参考:ContinueWith

コード例

Task.Run(() =>{
    //非同期処理
    return 戻り値;
}).ContinueWith(t =>{
    var result = t.Result;
    //後続の処理
}

async

asyncがついたメソッド=>メソッドが非同期であることのマーカー。

https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/async

About return value

voidではなく必ず、Taskを指定する。(戻り値は返せない。) Tを返したい場合、 Task<T>を指定する。

await Keyword(Case Task, Task<T>

await Keywordのついた処理を実行する場合、

  • await Keywordが付与された処理をスレッドプールで実行する。
  • メソッドをどこまで実行したかを記録する。
  • gotoラベルをawait Keywordが付与された処理の後に挿入する。
  • スレッドプールの処理が完了済の場合は、後続の処理を流す。
  • スレッドプールの処理が未完了ならContinueWithで自分自身をコールバック登録(=スレッドプールに預けた処理が終わったら再帰呼び出し
  • 再帰呼び出しの時、貼っておいたラベル位置までgoto といった処理を勝手に展開してくれる。(a.k.a. StateMachine)

つまり、async / awaitは、中を開けると、(Taskの場合)ContinueWithを利用して、I/O待ちの展開や、I/O待ち終了後の処理再開を制御するコードをキーワード一発で書ける仕組み。 そして、TaskはThreadPoolを、便利に使う仕組み。

async / await Bad Practices

async void is bad;

public async void GetHogeAsync() とかやると、メソッド内でawaitが出来ない。そして、例外も受け取ることが出来ない。 async Taskだと、awaitで終了待ちが出来る。例外を受け取ることも出来る。

async voidを書かざるを得ないのは、WinForm等でイベントハンドラを作る場合のみ。(async voidじゃないと非同期対応できないので仕方なく残っている。)

async voidメソッドの処理が完了するまでにスレッドプールに預けた非同期処理が完了しない場合、 System.InvalidOperationExceptionで落ちます。 ※ async voidメソッド本体の処理が遅くて、スレッドプールに預けた非同期処理が高速に動作している時は発覚しない負債です。

(async returned)Task.Wait is bad;

async メソッドの戻り値のTaskを.Waitしてはいけない。 => デッドロックで死ぬため。

var t = MailClient.SendAsync(new …省略);

t.Wait();

とした場合

1.t.WaitでUIスレッドをロックする。

2.MailClient.SendAsyncは、スレッドプールからUIスレッドに制御を戻そうとする

3.ロックされたUIスレッドに制御を戻せず、デッドロックで処理継続不可能

となる。

Taskは、await すべし。

Can't Write async Constructor;

C#ではasync Constructorは書くことができない。(そもそも構文エラーになる。※ C#9現在)

が、Constructorの発火でもってそのObjectを利用可能とするという役割の原則に則ると、asyncメソッドを呼びたくなる時がある。

(例):MailClientのWrapperを書く場合等であれば、MailServerへの接続や認証までをConstructorで行いたいけれど、これらは同期処理ではなく、I/O待ちで行いたい(ネットワーク越しの処理のため。)

その場合、staticなCreateAsyncを生やしてあげる必要がある。

Docker上にSqlServerをセットアップして、.dacpacの適用を行う

やりたいこと

Docker上にSqlServerをセットアップして、.dacpacの適用を行う。

前提条件

実際にやること

  • Docker上にSqlServerをセットアップする。
  • .dacpacの適用を行う。

ここに書いたDockerfileがあります。

FROM mcr.microsoft.com/mssql/server:2017-latest as Builder

ENV ACCEPT_EULA Y
ENV SA_PASSWORD h0geFuga
ENV MSSQL_PID Developer
ENV MSSQL_LCID 1041
ENV MSSQL_MEMORY_LIMIT_MB 4096

RUN apt-get update && apt-get install -y --no-install-recommends unzip curl \
    && apt-get clean \
    && curl -Lq https://go.microsoft.com/fwlink/?linkid=873926 -o sqlpackage-linux-x64-latest.zip \
    && ls -alh \
    && unzip sqlpackage-linux-x64-latest.zip -d /opt/sqlpackage \
    && chmod +x /opt/sqlpackage/sqlpackage \
    && apt-get purge -y --auto-remove unzip \
    && rm -rf /var/lib/apt/lists/*

COPY KashiLogDB.dacpac /tmp/kashilogdb.dacpac

RUN ( /opt/mssql/bin/sqlservr --accept-eula & ) | grep -q "Service Broker manager has started" \
    && /opt/sqlpackage/sqlpackage /a:Publish /tsn:localhost /tec:False /tdn:KashiLogDB /tu:sa /tp:h0geFuga /sf:/tmp/kashilogdb.dacpac \
    && rm /tmp/kashilogdb.dacpac \
    && pkill sqlservr

Dockerfile Is 何

続きを読む