ローマ・ベネチアに遊びに行く

久しぶりに海外ネタ(海外移住ではない)。

今年の夏、思い立ってイタリアはローマ・ベネチアに遊びに行った。
ローマ7泊、ベネチア3泊のお大尽旅行(日本の弾丸ツアー旅行の6泊8日の皆様、ごめんなさい)。
ゆったり、たっぷり、のーんびりな大変楽しい旅行だった。


なにせこのブログ、キラキラな「ローマ旅行中の私、素敵」なことを書くつもりは毛頭ない。
例によって備忘録だ。

  • 治安

日本の旅行サイトを見ると「ローマはスリが多発」「駅バス地下鉄は犯罪者の巣窟」「鞄は"肩掛け"も"後ろに背負う"もダメ絶対!」「人を見たら泥棒と思え」。
行きましたよ、ローマ駅。
まぁ20-30分に一回、悲鳴が轟いて、あわただしい音がして、数分後には誰かが床に押さえつけられてた。
でも、正直思ったほどではない。
他の国からの観光客、背中にリュックを背負い、足元にスーツケーツを放り投げ、そりゃやられるわ。
でも、絶えず周りを見回して、怪しい人が背後から近づいて来ないか警戒するほどではない。
荷物も最小限にして、小さめのバッグを袈裟懸けにして、前にしていればまず何もない(まずそんな警戒している奴には近づかない)。
もちろん、荷物で場所取りしてお買い物、なんてやったら秒で荷物はなくなるが、普通に気を付けていれば問題なし。

もちろんそれには理由がありそう。
駅にはほぼ10m間隔で警察の方がいるし、シーズン前には相当な掃討がされた模様。
バス・地下鉄、メジャーな観光スポット同様。
ローマは観光都市なので、観光シーズンには受け入れ側がかなり気を使ってくれている、ということらしい。

  • バスの移動

曰く「事前にチケットを買わないとダメ」「イタリア人は英語もできないからチケットを買うのが大変」などなど。
いえいえ、無問題。
おそらくCOVIDの間に電子決済が導入されたのだろう、乗ってから検札機にNFC付きのクレジットカードぴっ!で完了。
同じカードで複数人使えないので、家族で旅行する場合には家族人数分クレカが必要。
検札は結構頻繁に来て(7泊の滞在中に2回遭遇)、その場で払えないと40ユーロの罰金なので注意。

  • コミュニケーション

さすが観光都市、おおよそほとんどの所で英語が通じる。
しかも彼らもヘタなので、お互いに気を使って理解しあう、敬愛の心がある。
TOEIC600点台の英語なら、無問題でしょう。

  • レストランの注文、支払

イタリアだもん、そりゃ旨いもん食いたいさ。
人気店は混んでいるので、予約をしろ。
席についてからも、注文まで結構待たされる。
でもこっちも慣れないメニューを読むのに四苦八苦するので、とりあえず飲み物だけ頼んで時間を稼ごう。
よく言われる「日本人はパスタ・ピザしか注文しないので歓迎されない」は嘘。
周りのアメリカ人もパスタ・ピザしか注文してない、さすがWe the people of the United States、In Rome Do as the Roman does(郷に入れば郷に従え)など気にしない。
でもパスタ・ピザしか注文しないのはもったいない、何故なら他のメニューが段違いに旨いから。
「ローマではカルボナーラとアマトリチアーナを」とよく書かれているが、パスタはバリカタ、味はめちゃ塩辛い。
一方前菜や肉料理 - ちょー控えめに言って最高。
よく考えて注文するが吉。

さて支払い。
米国では基本テーブル支払いなのだが、イタリアはちょっっっっと違う。
いわゆるレストランはテーブル支払、テーブル担当がテーブルに請求書を持ってくるので、電子端末でそこで支払い。
トラットリアはだいたいキャッシャー支払、どこに座っていたかを言えば、そこで請求書が出て電子端末で支払い。
それ以下は前払いなので、注文するカウンターで支払う。
なので、トラットリアでテーブルで待っていると「もう一杯飲む?」と聞かれて・・・ええ、もちろん飲みますよ!
などと書いても写真もないと信じてもらえないので、一枚ぐらい載せておこう - これ以上控えめには言えません、最高!

Backgroundworkerの使い方

最近プログラミングのネタをほとんど投稿しない、何故か?
それは最近の職務がプログラミングだから。
教師生活25年、ついについに、プロのプログラマーに・・・小学生の頃からいわゆるバイナリーでプログラムをベタ打ちしていたことを考えると大変感慨深い。
あの頃にプログラムや変数がとどのつまりは実行メモリー上にある何かだと学んだことは、現在の仕事の礎になっている。


そんな感傷はさておき、久々の趣味グラマー。
大量のファイルの処理などの重い処理をUIスレッドでやらせると、UIが凍る、アプリが反応しなくなる。
これを防ぐために、UIアプリでは処理スレッドをマルチスレッド化して、UIスレッドの処理から分離をする。
C#にはTaskというクラスがあり、このブログでも一度取り上げている。
C++のスレッドに比べれば極めて簡単にマルチスレッド化できる。
今回取り上げるBackgroundworkerはUIスレッドに特化したもので、例えば処理中に"現在処理中です、X%処理済み"のような表示をさせるものだ。
MSFTからも懇切丁寧なドキュメントが公開されている。
learn.microsoft.com
いつも通り、何でも作ってやってみよう。


まずFormを作る、環境はVisual Studio 2022、.NET8を使用する。

プロジェクトテンプレートからWindows Form Applicationを選択する。
frameworkは.net framework 2.0以上なら良いのだが、今回は最新の.NET 8を使用する。
プロジェクト名は"TestBackgroundWorker"。
テンプレートが出来上がったらスケルトンビルド(何も変更せずにビルド)してdebugモードで実行しておくのはお約束。

次にFormに必要な部品を組み込む、今回は

  • Button x 2
  • Label
  • Backgroundworker

の4つだ、ツールボックスからFormに放り込み、適当に配置する。

BackgroundworkerはTimer同様に欄外に配置される。

お次に各部品のイベントハンドラーを起こす。
各部品を選択して、プロパティウィンドウから次のイベントハンドラーを作る。

  • Button: Click
  • Backgroundworker: DoWork、ProgressChanged、RunWorkerCompleted

適当なメソッド名をつければ、Formクラスにイベントハンドラーがテンプレートされる。
最近のVisual Studioはこの辺りを秘匿しなくなったので、Form.Designer.csを見ればどのようになっているか一目瞭然だ。
筆者のはこんな感じ。

        private void InitializeComponent()
        {
            buttonStart = new Button();
            buttonCancel = new Button();
            labelProgress = new Label();
            backgroundWorkerTest = new System.ComponentModel.BackgroundWorker();
            SuspendLayout();
            // 
            // buttonStart
            // 
            buttonStart.Location = new Point(112, 219);
            buttonStart.Name = "buttonStart";
            buttonStart.Size = new Size(112, 34);
            buttonStart.TabIndex = 0;
            buttonStart.Text = "Start";
            buttonStart.UseVisualStyleBackColor = true;
            buttonStart.Click += OnBtnStartClick;
            // 
            // buttonCancel
            // 
            buttonCancel.Location = new Point(350, 219);
            buttonCancel.Name = "buttonCancel";
            buttonCancel.Size = new Size(112, 34);
            buttonCancel.TabIndex = 1;
            buttonCancel.Text = "Cancel";
            buttonCancel.UseVisualStyleBackColor = true;
            buttonCancel.Click += OnBtlCancelClick;
            // 
            // labelProgress
            // 
            labelProgress.AutoSize = true;
            labelProgress.Location = new Point(86, 43);
            labelProgress.Name = "labelProgress";
            labelProgress.Size = new Size(59, 25);
            labelProgress.TabIndex = 2;
            labelProgress.Text = "label1";
            // 
            // backgroundWorkerTest
            // 
            backgroundWorkerTest.WorkerReportsProgress = true;
            backgroundWorkerTest.WorkerSupportsCancellation = true;
            backgroundWorkerTest.DoWork += bgWkrTestDoWork;
            backgroundWorkerTest.ProgressChanged += bgWkrTestProgressChanged;
            backgroundWorkerTest.RunWorkerCompleted += bgWkrTestRunWorkerCompleted;
            // 
            // Form1
            // 
            AutoScaleDimensions = new SizeF(10F, 25F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(800, 450);
            Controls.Add(labelProgress);
            Controls.Add(buttonCancel);
            Controls.Add(buttonStart);
            Name = "Form1";
            Text = "Backgroundworker Test";
            ResumeLayout(false);
            PerformLayout();
        }

最後にイベントハンドラーをしこしこ実装する。
前述の通りイベントハンドラーはForm.csに全てテンプレートされているので、以下のように実装する。

    public partial class Form1 : Form
    {
        static int DummyLoadTimeInMsec = 500;
        static int AmountOfWork = 20;
        public Form1()
        {
            InitializeComponent();
            labelProgress.Text = $"Not Started";
        }

        private void bgWkrTestDoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            for (int countWork = 0; countWork < AmountOfWork; countWork++)
            {
                if (worker.CancellationPending == true)
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    System.Threading.Thread.Sleep(DummyLoadTimeInMsec);
                    int progressPercentage = countWork * 100 / AmountOfWork;
                    worker.ReportProgress(progressPercentage);
                }
            }
        }

        private void bgWkrTestProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            labelProgress.Text = $"Progress: {e.ProgressPercentage.ToString()}% completed";
        }

        private void bgWkrTestRunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled == true)
            {
                labelProgress.Text = $"Canceled";
            }
            else if (e.Error != null)
            {
                labelProgress.Text = $"Error: {e.Error.Message}";
            }
            else
            {
                labelProgress.Text = $"Completed";
            }
        }

        private void OnBtnStartClick(object sender, EventArgs e)
        {
            if (backgroundWorkerTest.IsBusy != true)
            {
                backgroundWorkerTest.RunWorkerAsync();
            }
        }

        private void OnBtlCancelClick(object sender, EventArgs e)
        {
            if (backgroundWorkerTest.WorkerSupportsCancellation == true)
            {
                // Cancel the asynchronous operation.
                backgroundWorkerTest.CancelAsync();
            }
        }
    }

「1文字変数名は早漏・短小のやること」「ハードコードは悪」だ。
最近はString.Formatも使わず、文字列補間式($"{}")を使っている。
これを使うと文字列書式に変数名やメソッドを直接ぶっこめるので、より直感的にコーディングができる。
ところでこの実装の肝は

  • BackgroundworkerオブジェクトのRunWorkerAsyncを実行すると、DoWorkのイベントハンドラーであるbgWkrTestDoWorkが実行される
  • DoWorkの中で、worker.ReportProgressに処理の進行状況を%で渡すと、ProgressChangedのイベントハンドラーであるbgWkrTestProgressChangedが呼ばれてUIが更新される

といったところだ。

こいつをビルド、実行してStartボタンを押せば、UIスレッドは止まらずにバックグラウンドで重い処理(ここでは500msecのスリープを20回実行)することができて、その進捗がUIスレッドに反映される。
止めたいときにはCancelボタンを押せばよろしい。


さて、何でもUIスレッドに実装するのは阿呆のやること。
DVAのように、処理とUI系は分離するのがよい。
どうしたらよいか?

まず以下のような処理クラスを作る。

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

namespace TestBackgroundWorker
{
    internal class DemandingWork
    {
        static int DummyLoadTimeInMsec = 500;
        static int AmountOfWork = 20;
        public DemandingWork() 
        { }
        public void DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            for (int countWork = 0; countWork < AmountOfWork; countWork++)
            {
                if (worker.CancellationPending == true)
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    // Perform a time consuming operation and report progress.
                    System.Threading.Thread.Sleep(DummyLoadTimeInMsec);
                    int progressPercentage = countWork * 100 / AmountOfWork;
                    worker.ReportProgress(progressPercentage);
                }
            }
        }
    }
}

次にこのクラスのインスタンスをFormのメンバーにする。

        private DemandingWork demandingWork;

FormのInitializeComponentで実体化する。

            demandingWork = new DemandingWork();

BackgroundworkerのDoWorkのイベントハンドラをDemandingWork.DoWorkにする。

            backgroundWorkerTest.DoWork += delegate (object sender, DoWorkEventArgs e)
            {
                demandingWork.DoWork(sender, e);
            };

一時delegateを作っているが、λ式で一発で行ってもよい(筆者はλ式が苦手な年寄、ぐおふぉんぐおふぉん)

こりだけ、詳細はこちらから。
github.com

今回の装備一覧

久しぶりの海外旅行、しかも個人。

  • Surface Pro 10 (会社・個人兼用、色が赤いは3倍速い仕様)
  • iPhone 13 Pro (US回線)
  • F(x)tec Pro1 X (現地回線)
  • Lenovo Tab M10 Plus (機内エンタテイメント)
  • Jabra 85t

今回は旅の途中で支社によって、そこでリモート勤務の予定なので、会社のPCに個人のアカウントも設定して共用した。

それでは行ってきまいる。

Zen3は燃えているか

過日デスクトップPCのCPUをRyzen 5950Xに更新した。
このデスクトップPCはWindows 11対応のために2021年末に組んだものだが、当時は半導体供給不足の波をざっぱーんと被り、16コアのRyzen 5950Xはとても手が出ず8コアのRyzen 5800Xで組んだのだ。
1年も経てば安くなるからCPUを入れ替えればよいかと思っていたのだが、価格はなかなか下がらず、今年の頭にようやくRyzen 5950Xに入れ替えたのだ。

さて使いだしてから3か月、最近なぜかストンストンと理由もなく落ちる。
ははぁ、さてはメモリーだな。
過去にもあったぞ。
最近はメモリーはめちゃ安いから、買いなおしちゃえ、amazonぽちっとな。

うむ、治るどころか悪くなったぞ。
なんじゃごりゃ!

オーバークロックもしていないので見事なCPUオーバーヒートです。
このケース&冷却ではRyzen 5950Xは無理か?
amazonぽちっと、Ryzen 5800X買戻し。

げぼびびょん、なんじゃごりゃ!

どうも5950Xに換装したときにAIOのクーラーを痛めてしまったようだ。
もう一発、amazonぽちっと。

CPUもRyzen 5950Xに戻しの。


おー、ようやくまともな数字が、よかったよかった。

もともとこのデスクトップを組むときに、スペースに余裕がなくAIOのラジエター用のファンをケースファンとして共用したのだ。
どうも最初にRyzen 5950Xに換装したときにそのラジエターファンを破損 -> 徐々に動作しなくなる -> 液冷部がチンチンになりイカれた、だったようだ。
AIO交換時にケースを開けたときにはケースの中がむわんとするほど暑かった。
他の部品が一緒にやられず本当に良かった。
ついでにケース内の分解掃除も大掛かりにできて、本当に良かった。

Road to Kwumsy K2 mod (part 2)

youtu.be
The last step was how to put everything in the body.
This was my floor plan.

  • move the keyboard controller board to 7 o'clock direction, to accommodate custom USB-C cable connector and USB power bank
  • put USB power bank aside the keyboard control board
  • put Raspberry Pi on the keyboard controller board
  • install switch and USB charger connector to top right corner


First any conflicting bosses, pillars and supports were removed, to make sure the floor plan works.

Looking into the keyboard controller, all FFC & cables have marginal length, except touch controller FPC.
The FPC is 0.5mm pitch 6 contact.
I installed the FPC extension and long FFC.

New bosses were installed to hold the keyboard controller board.

Holes were punched and drilled to install switch and USB connector for charger.

Bosses were attached to Raspberry Pi board too.

This is finally assembly.

Power is distributed as below.

If you are interested, here are the links for 0.5mm 6 contact pitch FFC extension and FFC.
https://www.amazon.com/gp/product/B07RWNDFV1www.amazon.com
https://www.amazon.com/gp/product/B07RZ8M6M6www.amazon.com

Oh BTW - the enclosure screws are tricky, they are hex cap screws (some are trox but open-able by hex), you may need some special tool like this.
I replaced them with regular Phillips screws after all, they are M2, short ones are 4mm, long ones are 8mm.
www.amazon.com