うどん県出身グーナーの呟き

神奈川県在住のグーナーです。プログラムをやっているので勉強していることや作った便利ツールを公開したいと思います。

【pyenv】【python】Windows10/11にpyenvをインストールしてPython開発環境を整えてみたよ 2023年1月版【Windows】

概要

以前に投稿したwindows10でのpyenvを使ったPython開発環境構築方法が古新聞となっていたようなのでアップデート ryo-udon.hatenadiary.jp

以前まではgit clone して各種環境設定をする必要がありましたが、今は一つコマンドをコピペ実行するだけでインストールができるようです。 ただし少しハマりポイントもあったのでそこも解説します。

インストール方法

使用するpyenv-winはこちらになります。

ここのreadmeに書いてある通りに実行するのみです。

pyenvのインストール

ターミナルを管理者権限で起動し以下のコマンドを実行

Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"

これで$HOME直下にinstall-pyenv-win.ps1がダウンロード&実行されて同じく$HOME直下に.pyenvディレクトリが作成され、インストール完了となります。

ただし落とし穴も(スクリプトの実行権限)

もし購入したばかりのパソコンなどだとスクリプトの実行権限がありませんという文言が出てきてインストール失敗することがあります。

この場合はこちらのページに書いてある通り、以下のコマンドを管理者権限で実行したターミナルにて実行します。

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

本当に実行してもいいのか聞かれるので y を押してEnter.

これでスクリプトの実行ができるようになります

実行権限付与後、一度$HOME以下にある .pyenv, install-pyenv-win.ps1の二つを削除した上で再度pyenvのインストールを実行します

動作確認

最後に動作確認します。

ターミナルでpyenvと打ち込むと以下のようにバージョンが表示されればインストール完了です。

実際の使い方については以前の記事の中にあるpyenvの使い方を参照してください。

最後に

というわけで、簡単ですがインストール方法がかなり簡略化されていたのでアップデートしました。

今はTwitterbotを作っているので近々公開予定です。

ではでは。

【Python】【サンプルコード】実際の用途別チートシート を作ってみたよ【画像編集編】

実際の用途別チートシート を作ってみたよ【画像編集編】

概要

最近のスマホの画像が余りに高解像度です

それ自体は嬉しいのですが、Markdownで簡単なドキュメントをサクッと使おうと思うと意外とこれが障壁になることがあります。

そう。Markdownのドキュメントに張り付けると無茶苦茶大きいのです

というわけで今回はどんな画像もまとめて簡単にサイズを変更するスクリプトを書いたので備忘録に残します。

またそれ以外にも画像の編集などで見返すものをこちらのページに追記していきます。

画像編集に使うライブラリ

画像の読み込み、簡単な編集

PIL

画像の縮小

from PIL import Image
import glob
import os

path = "path/to/image/"
file_type = ".jpg"
filenames = glob.glob(path + "*" + file_type)
filenames

# リサイズした画像を格納するディレクトリ作成
os.makedirs(path+"resized")

# 画像を読み込み、その後リサイズして保存
for filename in filenames:
    img = Image.open(filename)
    fn = os.path.basename(filename)
    img_resize = img.resize((800,600))
    img_resize.save(path+"resized/"+fn)

【Python】【pyenv】pyenv-winとWSL内のpyenvが干渉したので直してみた

pyenv-winとWSL内のpyenvが干渉したので直してみたよ

概要

先日以下の記事で書いたように、Windowspythonを入れていなかったのでpyenv-winをインストールしました。

ryo-udon.hatenadiary.jp

ただ正直Windowsでの動作確認程度の用途しかなく、そろそろ20.04のWSL環境にもpyenvを入れて運用しようとしてみたら、

あれ?動かなくない?

そう。動かないのです。

正確には~/.bashrcにpyenvのパスを設定するのですが、その際に以下のようなエラーがでます。

bash: /mnt/c/Users/pastm/.pyenv/pyenv-win/bin/pyenv: /bin/sh^M: bad interpreter: No such file or directory
HOME: command not found
bash: /mnt/c/Users/pastm/.pyenv/pyenv-win/bin/pyenv: /bin/sh^M: bad interpreter: No such file or directory

ん?pyenv-win?なぜpyenv-winを見に行くの?

どうやらWindows側の環境変数を参照しているらしく、pyenv-winの際に設定したPYENV_ROOTとPATHに引っ張られてwindows側のpyenvにアクセスしてしまっているようです。

というわけで今回はその解決方法を見つけたので備忘録がてら書いていきたいと思います。

直し方

先に直し方を説明します。

ちなみにこれは先にpyenvのインストール手順を踏んだ後に実行しても問題ありません。(あくまでPATHの問題なため)

直し方はこちらのredditの記事を参考にしました

直し方はシンプル。

/etc/profile に以下の一文を追加するだけ。

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib:/snap/bin"

何をしているかというと、単純にPATHをここで上書きしています。

後は

source /etc/profile
source ~/.bashrc

でこのPATH問題は解決します。

ついでにpyenvのWSL2 Ubuntu20.04へのインストール手順

こちらは何度も焼き増しされていますが、こちらの記事を参考にしました。

まずは各update, upgrade(久々に起動したせいか、かなりの量があってびっくり)

sudo apt update
sudo apt upgrade

次に各種ライブラリのインストール

sudo apt install -y build-essential libffi-dev libssl-dev zlib1g-dev liblzma-dev libbz2-dev libreadline-dev libsqlite3-dev libopencv-dev tk-dev git

次はpyenvの本体のインストール。UbuntuなどのLinuxではgitからリポジトリをクローンしてきます。

ここでは丁度一週間前にv2.3.1がリリースされていたのでこちらにしました。

git clone https://github.com/pyenv/pyenv.git ~/.pyenv

cd ~/.pynev

git checkout v2.3.1

最後に問題になった各種PATHの設定

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc

echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc

echo 'eval "$(pyenv init --path)"' >> ~/.bashrc

source ~/.bashrc

これでインストールは完了です。

最後に

というわけで最初はpyenvが使えなくて焦りましたが、結論から言えば割と簡単に直すことができました。

また何か不具合などがあれば随時更新したいと思います。

ではでは。

Docker + WSL2 をインストールしてみた + ROSも動くようにしてみた。

Docker + WSL2 をインストールしてみた + ROSも動くようにしてみた。

概要

最近開発環境を何度も複製する機会があり、そろそろいい加減開発環境を簡単に複製できるようにすべきだなーと思い、重い腰をあげてDockerをインストールしてみましたのでまとめてみます。

WSL2インストール

こちらは過去のこちらの記事を参照ください。

Docker Engine インストール

今回、Docker Desktopは無しでインストールしたいと思います。

理由はDocker Decktopは商業利用が有償なため、個人利用でこれに慣れすぎるといざ仕事で使いたいと思ったときに悪影響がでそうだなと思ったからです。

では、早速インストールしていきます。

今回はこちらこちらを参考にしました。

必要なライブラリのインストール

以下のコマンドを入力

sudo apt install curl apt-transport-https ca-certificates gnupg lsb-release

Docker公式GPG鍵を追加

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Docker安定版のレポジトリを追加

echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

レポジトリのアップデートとDocker Engineのインストール

sudo apt install docker-ce docker-ce-cli containerd.iosudo docker-compose

ユーザをDockerに追加

sudo gpasswd -a (ユーザ名) docker

Adding user (ユーザ名) to group docker と出れば成功

Docker デーモンの起動

sudo service docker start

(余談) 下のテストでdocker run コマンドをたたいてpermission deniedが出る場合

これは、/var/run/docker.sockがユーザでも編集可能になっていないことが原因です。

なので、chmodします。

sudo chmod 666 /var/run/docker.sock

これで問題なくdocker コマンドを実行可能になります。

Dockerが動くかのテスト

こちらの公式にあるHello Worldコンテナで試してみます。

docker run hello-world

これでエラーなく起動できればDockerのインストール成功です。

さて本題。WSL2 上にROSをインストールしてみる

今回のモチベーション。DockerでWSL2上でGUIを使えるROSをインストールしてみました。

参考にしたのはこちら

以下のコマンドを起動するとROSが入ったUbuntuが起動します。

docker run -p 6080:80 --shm-size=512m tiryoh/ros2-desktop-vnc:dashing

後は、好きなブラウザで http://127.0.0.1:6080/ にアクセスするとGUI画面がブラウザ上に表示され、確認できます。

ここでは3D SimulatorであるGazeboが動くのを確認しています。

終わりに

というわけでWSL2でROS環境を構築してみました。

今後はDOckerの勉強をしつつ、自動で静的解析をしてくれるような環境の構築などもやっていきたいなとおもっています。

ではでは。

【pyenv】【python】Windows10にpyenvをインストールしてPython開発環境を整えてみたよ【Windows】

pyenv-win をWindows10にインストールしてPython開発環境を整えたよ

概要

最近C++やhtmlなどばかりやっていたせいか、windows環境にPythonを入れていないことに先ほど気づいたので入れてみました。

個人的にやっぱりこのあたりの環境構築はLinux, Unix系のほうがやりやすいなという印象。

何ならこの間WSLを入れたので、最初からそっちで開発すれば良かったのではないか説もあります。。。

それはさておき、pyenv-winのREADMEにインストール方法がまとまってはいるのですが、意外と落とし穴もあったのでそこを備忘録がてらまとめたいと思います。

そもそもpyenvってなに?

pyenvとは大量にあるPythonの環境を簡単に切り替えてくれる便利ツールです。

Pythonは現在リリースバージョンで3.9.6まで出ています。

Pythonを初めて使う人は何も考えずに最新のリリースバージョンをインストールすればいいのですが、

長年Pythonを使って開発していると昔のバージョンなら使えた機能が無くなるや形式が変わるなどといった問題が出てくることがあります。

もちろんライブラリやシステム側でそういったバージョンの違いを吸収できるように作るべきなのですが、それも中々に大変な作業です。

そこで、このシステムを使う時はPythonのこのバージョンを、という形でバージョンを切り替える機能が求められているわけです。

そこで活躍するのがpyenvです。

pyenvは複数のpythonバージョンを仮想環境として保持することができ、その環境間を簡単に切り替えることができます。

というわけで、Pythonで開発する上で欠かせないpyenvをインストールしたのでその手順を説明していきます。

(余談)Anaconda

実はpyenvの他にAnacondaと呼ばれる、pythonバージョンを管理できるとても便利なツールがあったのですが、

つい最近商業利用が有償になってしまいました。

今回、個人利用しか考えていませんが、念のためAnacondaは使わずpyenvのみで運用していきます。

pyenv-winインストール手順

pyenvはもともとLinux, Unix(Mac)向けのツールになっていて、そのままではWindowsでは使えません。

ですが、最近ではそれをWindowsでも使えるようにしてくれたpyenv-winGithubで公開されています。

Install方法についてもREADMEに簡潔にまとめられており、かなり簡単にインストールできるようになっています。

開発者の方には頭が上がりません。

1. pyenv-win ダウンロード

まず初めにpyenv-winのパッケージをインストールします。

Githubから取ってくる形になるので、インストールは主に以下の二つの方法があります。

  • zipファイルをダウンロードする
  • git cloneしてくる

まず最初に、最終的にインストールするとどういうディレクトリ構成になるかを紹介します。

C:\Users\<User>\.pyenv
├───pyenv-win
    ├───bin
    ├───libexec
...

zipファイルをダウンロードする場合

  1. リンク先からpyenv-winをダウンロードします。
  2. 『.pyenv』ディレクトリ(フォルダ)がない場合、『C:\Users(自分のユーザ名)\』に.pyenvディレクトリを作成します。
  3. ダウンロードした.zipを解凍し、中に入っているpyenv-winを2.で作った.pyenvの中に移動します

git cloneする場合

git clone する場合は以下のコマンドをたたくだけです。

git clone https://github.com/pyenv-win/pyenv-win.git "$HOME/.pyenv"

2. Pythonアプリインストーラの無効化

ここから先に進む前に自分のwindowsのバージョンを確認してください。

Windows10 1905よりも新しいバージョンの場合、Python App Installerがデフォルトで有効になっています。

その場合、ここから先の作業をするまえに無効化する必要があります。

やり方は簡単です。

下の画像のように左下に『アプリ実行エイリアスの管理』と打ち込んで検索をかけて、実行してください。

すると次のようにアプリの一覧が出てきますので、この中からPython, Python3のアプリインストーラをオフにしてください。

3. pyenv-winの環境変数を設定する

次に.pyenvに移動したpyenv-winを実行できるようにpyenvの環境変数の設定をしていきます。

まず、左下のスタートメニューを右クリックし、Powershellを起動します。

その後、以下のコマンドを実行します。

[System.Environment]::SetEnvironmentVariable('PYENV',$env:USERPROFILE + "\.pyenv\pyenv-win\","User")
[System.Environment]::SetEnvironmentVariable('PYENV_HOME',$env:USERPROFILE + "\.pyenv\pyenv-win\","User")

これでpyenvの環境変数は設定完了です。

4. Pathを設定する

最後にパソコンがpyenvを見つけられるようにPathを設定していきます。

同じくPowershellを開き、以下を実行します。

[System.Environment]::SetEnvironmentVariable('path', $env:USERPROFILE + "\.pyenv\pyenv-win\bin;" + $env:USERPROFILE + "\.pyenv\pyenv-win\shims;" + [System.Environment]::GetEnvironmentVariable('path', "User"),"User")

pyenvが使えるかを確かめる

ここまで出来たら動くかを確認していきます。

ターミナルやpowershellを起動してもらい、以下を入力してください。

pyenv --version

これでダウンロードしたpyenvと同じバージョンが表示されればインストールの完了です。

また

pyenv

と打つとpyenvのコマンド一覧を確認できます。

pyenvの使い方

pyenvに様々なversionのPythonをインストールする (pyenv install)

このコマンドは様々なPythonのバージョンをインストールするコマンドです。

どのPythonがインストールできるかは

pyenv install -l

で確認ができます。

これを実行すると以下のようにインストール可能なバージョンが大量にリストになって表示されます。

この中からインストールしたいバージョンを選び次のコマンドを実行するとインストールが完了します。

pyenv install 3.9.6

インストール済みのPythonバージョン一覧を確認する( pyenv versions)

今、どのバージョンがインストール済みかを確認したい場合、こちらのコマンドを実行すると、

インストール済みのバージョンの一覧が表示されます。

また、pyenvの仮想環境が実行済の(現在すでに動いている)場合、動いているバージョンの頭に*がついて、どれが実行されているかを確認できます。

インストールした環境を実行する( pyenv exec )

pyenvの仮想環境を立ち上げる場合は以下のコマンドを実行します。

pyenv exec [バージョン]

なお、実行前にそのバージョンがインストールされている必要があります。

指定した環境を自動的に実行するようにする( pyenv global)

例えばバージョン3.9.6を常に自動的に実行されるようにしたい場合は以下のようにコマンドを設定します。

pyenv global 3.9.6

(余談)Vscodeの設定

VscodePythonの開発をする際Interpreterを設定しろと要求されますが、pyenvの場合簡単です。

Interpretorを設定せず、ただVscodeそのものを再起動します。

すると先ほど設定した環境変数をもとに勝手にVscodeが見つけてくれます。便利ですね。

注意: 再起動の際は必ずVscodeの全ウィンドウが閉じられているのを確認してください。Vscodeがパスや環境変数を読み込むのはVscodeが起動したときのみのようですので、pyenvのインストール時に設定した環境変数などが反映されません。

終わりに

というわけで、今回はwindowsPython環境を構築する方法について説明しました。

最近やっとwebページの構造が理解できてきたので、こんどはそれをDjangoなどのライブラリを使ってpythonベースのwebページなどを作っていきたいと思います。

ではでは。

【WSL2】【VSCode】Windows10にWindows Subsystem for Linux(Ubuntu 20.04)をインストールしてみた & VSCodeで環境を整えた【インストール方法紹介】【Ubuntu20.04】【Windows10】

Windows10にWindows Subsystem for Linux(Ubuntu 20.04)をインストールしてみた & VSCodeで環境を整えてみたよ

概要

C++のモジュールテストの勉強をしようとGoogle先生とお話していたところ、そういえばUbuntu環境を整えていないなと思い、前からやってみたかったWSL2, Ubuntu20.04のインストールとその開発環境を整えたので備忘録として残します。

WSLとは?

そもそもWSLとは何か。マイクロソフト公式サイトを見てみると以下のようにありました。

The Windows Subsystem for Linux lets developers run a GNU/Linux environment -- including most command-line tools, utilities, and applications -- directly on Windows, unmodified, without the overhead of a traditional virtual machine or dualboot setup.

"WSL(Windows Subsytem for Linux)とは、開発者に仮想マシンデュアルブートのインストールを必要とせずに、Windows上で直接GNU/Linux環境(例えばコマンドライン、アプリケーションなど)を実行できるツールです。"

かつて、プログラマ=Macという時代がありました。

(OSの歴史は簡単にまとまっているこちらのサイトが参考になると思います)

その最大の要因は、MacUnix系のOSのため、Linuxチックにソフトを開発できるということがメリットとしてありました。 (コマンドもLinuxと同じものが多い)

対してWindowsIBMと共同開発していたMS-DOSの系譜なので、コマンドラインなどが上のMac, Linuxとは違っていました。

世間的にはWindowsのほうがシェアが大きいですが(90%以上)、意外と組み込み系はLinuxベースの物も多く、特に研究用途などではUnixベースで書かれることが多くありました。

あと、個人的な意見ですが、コマンドラインで環境を構築しずらかったのもWindowsが避けられていた原因の1つだと思います。

というような背景もあり、しばらくプログラマ=Mac (or Linux)という状態が続いていたのですが、数年前(2016年)ついにWindowsが動きました。

そう、WSL(Windows Subsystem for Linux)のリリースです。

これによって、WindowsでもLinux, Unixベースのソフト開発ができるようになったためよりWindowsが優位になったのです。

(個人的にはいまだにWindowsはイライラする点が多いですが。。。)

WSLは何ができるの?

じゃあ、WSLは何ができるのか。

基本的にWSLはコマンドラインで動かす形になりますが、Ubuntuなどを入れることで簡単なLinuxのコマンドからGUIアプリケーションまで幅広く実行できます。参考

自分みたいにUbuntuのためにRaspberry PiUSBメモリを用意するといった作業が必要なくなります。

どうやってWSLをインストールするの?

基本的には公式サイトに沿ってコマンドを打ち込んでいくだけです。

Windowsのバージョン確認

まず、Windowsのバージョンを確認します。

以前はWindows Insider Programに参加する必要があったはずですが、なぜか自分は参加せずとも動かすことができました。

(もしかしたら手動インストールをする分にはInsider Programへの参加は必要がないのかもしれません)

ちなみに自分は以下のバージョンで実施しました。

エディション  Windows 10 Pro
バージョン 21H1
OS ビルド    19043.1110

上よりも新しいバージョンになっていれば問題ないと思います。

公式には以下のような記述があります。

WSL 2 に更新するには、Windows 10 を実行している必要があります。

x64 システムの場合:バージョン 1903 以降、ビルド 18362 以上。

ARM64 システムの場合:バージョン 2004 以降、ビルド 19041 以上。

18362 より前のビルドは WSL 2 をサポートしていません。 Windows 更新アシスタントを使用して、お使いのバージョンの Windows を更新します。

もし更新が必要な場合は以下の通りです。

更新方法

1 まず左下のWindowsマークから設定を開きます。

f:id:ryo_udon:20210723123340p:plain

2 設定の中から『更新とセキュリティ』を選択します。

f:id:ryo_udon:20210723123355p:plain

3 その後、赤丸で囲った更新プログラムのチェックを押してください。

f:id:ryo_udon:20210723123408p:plain

4 もしアップデートがあれば自動でアップデートしてくれます。

ただし、再起動が必要なアップデートがあれば可否が聞かれますので、再起動してもいいように他のアプリは落としておきましょう。

WSLのインストール

WSLには二つバージョンがあります。WSLとWSL2です。

違いはこちらの公式サイトに載っています。

基本的にはWSL2の方がパフォーマンスが上がること、制限なしのLinuxカーネルを利用できることがあげられてます。

唯一WSL2ができない(非推奨な)ことが、Windows <-> Linux間でファイルを同時に操作することですが、正直そのようなソフトを作ることはかなりレアケースだと思いますので、基本的には何も考えずにWSL2をインストールすればいいと思います。

(新しい物好きの自分は何も考えずにWSL2をインストールしました)

Powershellを管理者権限で開く

これから3つのコマンド(オプション機能を2個有効、WSLのバージョン変更)をPowershellで実行しますが、管理者権限が必要になります。

もし開き方が分からない方は以下の通りに実行してください。

  1. まず左下のWindowsマークを右クリックします

  2. Windows Powershell (管理者)から管理者権限を付与したPowerShellを実行できます

f:id:ryo_udon:20210723123518p:plain

LinuxWindowsサブシステムを有効にする

まずLinuxWindowsサブシステムというオプション機能を有効にする必要があります。

先ほど開いたPowerShellで以下のコマンドを実行してください。

dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

注意:ちなみにWSLをインストールする方はここで再起動をして"Linuxディストリビューションをインストールする"に進んでください。

仮想マシンの機能を有効にする

次に二つ目のオプション機能、仮想マシンプラットフォームを有効にします。

先ほどのPowerShellで以下のコマンドを実行してください。

dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

ここで再起動を求められますので「Y」を押してください。 (Yを押した瞬間に再起動しますので、びっくりするかもしれません)

Windowsが再度立ち上がったら次に進んでください。

Linuxカーネル更新プログラムパッケージをダウンロードする

ここではLinuxカーネル更新プログラムパッケージをインストールしていきます。

公式サイトのこちらのリンクからパッケージをダウンロードし、実行してください。

管理者権限を求めるウィンドウやインストールしますか、などを聞かれるのですべて「はい」を押してください。

WSL2を既定のバージョンとして設定する

再度PowerShellを開き(自分は念のため管理者権限で開きました)、WSLの既定バージョンをWSL2とするために以下のコマンドを実行します。

wsl --set-default-version 2

これで基本的な設定は終わりです。

Linuxディストリビューションをインストールする

さて、やっとLinuxをインストールしていきます。

上のパッケージをインストールすると、Microsoft Storeから様々なLinuxをダウンロードできるようになります。

ここでは例としてUbuntu20.04 LTSを入れていきます

上のリンクに飛んでいただくと入手ボタンがあるので、それをクリックします。

するとインストールするというボタンが上に現れますので、それもまたポチリます。

f:id:ryo_udon:20210723123738p:plain

これでインストールは終わりです。

Linuxディストリビューションのアカウントとパスワードを作成する

スタートメニューなどからLinuxディストリビューションを起動すると、最初の一回のみ以下のような画面がでてきます。

f:id:ryo_udon:20210723123807p:plain (撮り忘れたので公式より引用)

ここでユーザアカウント名とパスワードを設定すれば、WSL2 + Ubuntu20.04のインストールは完了です!!

WSL2 + VSCodeによる開発環境構築

ここからはWSL2とVSCodeを使った開発環境構築の方法を説明していきます。

こちらの方法は公式サイトにも載っています。

構築前に確認すべきこと

確認すべきことは主に以下の二つです。

  • WSLのインストールが完了していること
  • Windows側にVSCodeをインストールしていること

VSCodeがインストールできていない方はこちらのサイトからダウンロードしてインストールしてください。

VSCodeでリモート開発拡張パックをインストールする

VSCodeには様々な拡張機能を追加することができます。

例えば、プログラミング言語ごとのintellisense(補完機能)やデバッグ機能、自動でCMakeListを作ってくれる機能だったり、markdownのプレビューができるなど様々です。

自分がどういう拡張機能を使ってるかはまた今度紹介したいと思います。

さて、リモート開発拡張パックをインストールするのですが、ここで選択肢が二つあります。

公式サイトでは、Remote DevelopmentというWSLに限らず、他のパソコンや仮想マシンSSHでアクセスしてリモート開発できる拡張パックをインストールすることを推奨しています。

ですが、ただWSLでのみ開発することを考えている方にはこのパックはToo Muchな気がします。

また設定もいくつか必要となります。

なのでここでは、Remote WSLを紹介します。

どちらもMicrosoftが提供している公式拡張パックですが、後者はWSLに限定しています。

なのでほぼ何も考える必要もなくWSL上のUbuntuにリモートアクセスすることができます。

インストール方法は、リンク先のインストールを押すか、VSCode拡張機能から検索してインストールすることができます。

Remote WSLの使い方

1 まずVSCodeウィンドウの左下にある緑のボタンをクリックします。

f:id:ryo_udon:20210723123905p:plain

2 すると下のようなコマンド一覧がVScodeウィンドウの真ん中上部に表示されます。

f:id:ryo_udon:20210723123937p:plain

3 この中から『New WSL Window』を選択します。するとUbuntu20.04のディストリビューションに接続した状態のウィンドウが開かれます。

あとはいつものVScodeの感覚でファイル編集や操作ができます。

(余談)Linuxディストリビューションの切り替え方

ちなみに複数のLinuxを入れている場合(例えば18.04と20.04など)、簡単に切り替えができます。

  1. 先ほどと同じく左下の緑色のボタンをクリック

  2. コマンド一覧の中から『New WSL Window using Distro ...』を選択

f:id:ryo_udon:20210723123954p:plain

  1. 使いたいディストリビューションを選択

f:id:ryo_udon:20210723124004p:plain

で開く切り替えることができます。

終わりに

というわけで、今回はWSL2+Ubuntu20.04のインストールからVSCodeの設定までやってみました。

過去に山ほどLinuxインストールで苦しんできた身としてはこれほど簡単にインストールできるのは感動ものでした。

ぜひ皆さんも試してみてください。

ではでは!!

【C++】C++で簡単なマルチスレッドをやってみたよ【マルチスレッド】【サンプル】

C++ マルチスレッド処理を書いてみたよ

github.com

なぜやってみたのか

今回はマルチスレッド処理をC++で書いてみましたのでその紹介になります。

なぜマルチスレッドをしてみようとおもったのか。

それは最近センサの受け取って処理をまわすという部分を書いていて、まじめにマルチスレッドをやる必要があるなと感じたためです。

例えば10msごと(100Hz)にデータが送られてくるものを受け取って、50ms(20Hz)で処理を回したいとなったとき、どういう風に実装するべきでしょうか。

色々と方法はあると思います。

例えば、50msで回したい処理が実際は実行に20ms程度しかかからない場合、

それに加えて受信処理が短い時間で完了するのであれば、割り込み処理で十分かもしれません。

ですが、もし50msで回したい処理が40ms程度かかるものだった場合どういう方法があるでしょうか。

そう考えた時に思いつくのが、処理を複数に分ける(マルチスレッド)ということです。

処理を複数に分ける(マルチスレッド)、とは?

そもそも「スレッド」、「CPU」とは?

そもそも皆さんはパソコンの上で実行されるプログラムはどのようにして動いているかご存じでしょうか。

素子がどのように動くのかという細かい部分はおいておいて、基本的にC++などで書かれたプログラムはCPUで計算、実行されます。

ここでCPUの動きに注目します。

皆さん、パソコンを選ぶ時にこんな言葉を聞いたことはないですか?

  • クロック数
  • コア数
  • スレッド数

これが何か分かりやすく説明してくれているサイトがあるので先に紹介しておきます。

簡単に説明すると、下のようになります。

クロック数 = 頭の回転の速さ (例: 2.0GHz よりも 5.0GHzのCPUの方が計算能力が高い)

コア数 = 何個頭脳を持っているか (例: シングルコア: 1つ、 デュアルコア: 2つ、 クアッドコア: 4つ)

スレッド数 = 各頭脳(コア)が余裕がある時に何個並列で処理ができるか (4コア8スレッドという書き方だと、CPUで余裕があれば2個並列で処理して効率化できる)

すでにお気づきの方もいるかもしれませんが、

CPUの性能というのは一つの項目で決まるのではなく、基本的に上の三つの性能のバランスによって決まってきます。

ではどういう時にどの項目を重視すればいいのでしょうか。

クロック数最重視する場合

ここで処理の話も入ってきますが、例えばそのパソコンでは常にプログラムが1つだけ動くとしましょう。

こうなるとCPUに求められるのは、何よりそのプログラムを早く、安定して回すことになります。

こうなると他に処理をする必要がそもそもないので、コア数やスレッド数は小さくても問題がなくなります。

なので、マイコンなどと呼ばれるような組み込み系のコンピュータはコア数が少なく、シングルコア、デュアルコアが多いです。

(ここではマイコンを例に出しましたが、世の中にシングル、デュアルでそれだけクロック数が高いCPUが出回っていないので、例としては少しずれています)

コア数(あるいはスレッド数)を最重視する場合

例えば処理の重い(各コアの使用率が常に90%近くになるような)プログラムがパソコンの中で3個動くとしましょう。

この時点で察しの通り、上のようなクロック最重視、コア数が少ないものでは3つもの重い処理を回すことができません。

なので、ここではコア数が重要になります。

コア数が最低、その処理を回しきれるだけの数とクロック数を持っているかという確認が必要になるわけです。

(余談) じゃあパソコンを選ぶ時はどういうCPUを選べばいいの?

基本的に用途によりますが、日常的な使い方(ネットサーフィン、メールチェックなど)であれば、正直それほど悩む必要はないでしょう。

予算にもよりますが、Intelなら最低i3 ~ i5、Ryzenなら3以上を選んでおけばそうそう外れることはないでしょう。

(予算があるなら4コア8スレッドで2.0GHz以上のクロック数のものを買うととりあえず後悔はしないと思います。)

(さらに余談) でもパソコンはこれだけでは決まらない

上ではあまり言及しませんでしたが、家庭用パソコンだとCPU以外にもメモリ(一時的に処理しているデータを保存する場所、荷物の仮置き場)、ストレージ(データの倉庫)の二つにも注目する必要がありますので、なかなか決めるのは難しいかもしれません。

なので購入する際には周りの詳しい人に相談しましょう。

ちなみにお店の店員には相談しない方がいいかと思います。お得ですよといわれながら、結構な型落ちのパソコンなどを押し付けられることがあるらしいです。

マルチスレッドとは?

やっと本題です。

マルチスレッドとは、上のCPUの説明である程度察している方もいるかと思いますが、1つのプログラムで複数のスレッド(コア)を使って処理できるようにすることになります。

何がよくなるのかというと、簡単にいうと今まで2.0GHzのコア1つでしか処理ができなかった物が、2.0GHzのコア2つ(あるいはそれ以上)で処理ができるようになります。

なので理論上、プログラムをより高速で(リアルタイムで)実行することが可能になります。

ただし、ここで注意すべきなのは、あくまで理論上可能になるだけで、逆に速度が落ちる可能性もあります。

こういう話でよく聞くのは、最近はやりのGPUプログラミングです。

GPUというのはゲームなどで人や車が3Dで描画されているかと思いますが、その描画をより高速で行うことに特化した演算装置です。

CPUとの一番の違いはクロック数が低いコア数が圧倒的に多い(100倍から1000倍、最近のモデルではそろそろ10000倍になりそう)ことです。

なので、最近のAIやディープラーニングと呼ばれる膨大な並列計算を必要とする技術ではCPUではなくGPUを使って実装しています。

ここまで聞くと速くなる要素しかないですが、落とし穴があります。

それはどのように複数のスレッドに分散するかを決めるところです。

じつは意外と分散して処理をする直前の割り振りを決める処理が重くなって、全体の動作が重くなるということが多々あります。

(最近は優秀なライブラリなどのおかげで減ってきているようですが。。。)

なので、ここで言いたいのは、マルチスレッドをやる前に、「本当にマルチスレッドは必要なのか」「速くなりそうな処理なのか」を判断する必要があります。

分からないから取り合えずも全然ありだと思います。

なので処理時間で悩まれてマルチスレッドをと考えているそこのあなた、とりあえずまずはシングルスレッドのままで処理の効率化を頑張りましょう!!

本命のソースコード紹介

github.com

ここでは上のレポジトリ内にあるudp_pub_test.cpp, udp_sub_test.cppを紹介していきます。

この二つはローカルでUDP通信を行い、pub_testからデータを送信します。

UDP通信についてはまた別の記事で紹介するので、ここでは二つのプログラムの間をUDPっていう通信方式でデータを渡している、とだけイメージしてください。

sub_test側は二つスレッドが立っており、1つは常にデータの受信を待ち続け一定数データが溜まるとデータを読んでいいよフラグを立てます。 もう1つのスレッドは毎ループ、そのフラグを確認し、データが溜まっていればそれを読みに行って、画面に表示するという簡単なプログラムです。

ここでポイントとなるのは以下の二つになります。

  • スレッドの立て方
  • mutexのかけ方

ソースコードを追いながら順番に説明していきます。

スレッドの立て方

上の概要で説明したように、sub_test側では二つのスレッドが立っています。

  • データ受信
  • データ解釈

スレッドを立てているのは以下の部分です。 基本的にスレッドを立てる上で使用しているライブラリはC++11にデフォルトで入っている下の二つのライブラリです。

#include <thread>
#include <mutex>
int main(void)
{
    struct sockaddr_in addr;

    addr.sin_family = AF_INET;
    addr.sin_port = htons(12345);
    addr.sin_addr.s_addr = INADDR_ANY;


    std::thread th1(ReceivePacket,addr);
    std::thread th2(PointPurseMain, 20);
    th1.join();
    th2.join();

    return(0);

}

std::threadで宣言しているのが各スレッドになります。

ここで別スレッドで実行する関数を指定したあと、その下のjoin()関数を実行することで、別スレッドで処理が実行されます。

ちなみに上ではth1でデータ受信の関数名とその引数であるsockaddr_in(UDP通信用)を、th2でデータ解釈をする関数名と引数である関数を回すHz数を与えています。

簡単ですね。

mutexとは?

ここからがマルチスレッドで難しいところです。

マルチスレッドの処理を書いた時に一番陥りがちなのが、メモリのアクセス違反です。(実行時にSegmentation Faultなどとでるエラーです)

これはなぜ起きるのか。

パソコンにはデータを一時保存するメモリと呼ばれる装置が搭載されています。

基本的にプログラムを実行した時の変数だったりはこのメモリに一時保存されます。

メモリの中は賃貸の集合住宅のように区分けされていて、ここはしばらくの間、この変数さんの部屋よ、という形で確保されていきます。

ここで上のアクセス違反という言葉と併せて予想がついた方もいるかと思いますが、この各部屋には一度に一人の人しか出入り(書き込み)できません。

f:id:ryo_udon:20210703131940p:plain

中がショールームのように固定されていて、外から覗くだけであれば人数制限はありません。(いやな世界ですね。。。)

ただし、誰かが部屋の中に入ると、すべての窓はカーテンが閉められ、誰も見てはいけない状態になってしまいます。

あとは簡単ですね。そんな状況で家の中に入ろうとしたら通報されます。(不法侵入or覗きですね)

その通報された結果がSegmentation Faultです。

f:id:ryo_udon:20210703131839p:plain

じゃあ、これを防ぐためにどうすればいいのか、それをするのに必要なのが、

  • アクセスしていい変数(部屋)を別に用意する
  • アクセスする前に誰もいないかの確認をする

の二つになります。

ちなみに後者がここでメインで説明するmutexのことになります。

アクセスしていい変数を別に用意する

関数を見ながら説明していきます。

まず1つ目の説明をするために、データ受信部分を見ていきます。

void ReceivePacket(struct sockaddr_in addr)
{
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    bind(sock, (struct sockaddr *)&addr, sizeof(addr));

    uint8_t tmp_buf[BUFFER_SIZE];
    uint8_t* p = tmp_buf;

    int point_num = 0;
    int point_limit = POINT_BUFFER_LIMIT;
    int point_size = SINGLE_POINT_DATA_SIZE;
    int point_id = 1;

    while(1)
    {
        recv( sock, tmp_buf, sizeof(tmp_buf), 0);
        memcpy( p, tmp_buf, point_size);
        p += point_size;
        point_num++;

        if(point_num > point_limit)
        {
            printf("Receive Func:PointLimit\n");
            std::lock_guard<std::mutex> lock(mtx_);
            memset(buf_, 0 , sizeof(buf_));
            memcpy(buf_, tmp_buf, point_num * point_size);
            memset(tmp_buf, 0, sizeof(tmp_buf));
            p = tmp_buf;
            point_num = 0;
            data_set_flag_ = true;
        }

    }
    close(sock);

}

内容はいたってシンプルです。

毎ループ、データが来るのを待って、データが来たらそれをBuffer(データを格納するスペース)にポコポコ入れてあげるだけです。

そのあとに一定数データが溜まったら上で書いたフラグを立てた上で、アクセスするようの別のBufferにコピーします。

そうここでコピーしている先の別のBufferが上にあげた1つ目になります。

ただ、こちらについては必須ではありません。

先ほど話したように、各メモリの書き換えができるのは一度に1つのみです。

なので、他のスレッドがアクセスしている間、そのメモリにアクセスしないのであれば、こちらのように別にBufferを用意する必要はありません。

アクセスする前に誰がいるかを確認する(mutex)

イメージは各メモリ(部屋)に入る扉に、在室、退室の看板が立っているイメージです。

入る時は在室にして、出る時は退室にしましょう。入る前には看板を確認して、在室になっていたら待ちましょう。

mutexはただそれを簡単に行ってくれるだけです。

では簡単にソースコードを見ながら簡単に説明していきます。次に見ていくのは解釈部分です。

void PointPurseMain( int hz )
{
    std::chrono::system_clock::time_point start, now;
    start = std::chrono::system_clock::now();
    now = std::chrono::system_clock::now();
    double now_process_time = std::chrono::duration_cast<std::chrono::milliseconds>(now-start).count();// to milliseconds

    double process_target_time = 1000 / (double)hz;
    int process_time = 0;

    int point_num = POINT_BUFFER_LIMIT;
    int point_size = SINGLE_POINT_DATA_SIZE;
    int point_id;

    while(1)
    {

        std::lock_guard<std::mutex> lock(mtx_);
        if(data_set_flag_)
        {

            for(int i=0; i<point_num; i++)
            {
                point_id = i;
                printf("Main Thread:%d of points are set!! %d th point is (%d, %d, %d, %d)\n", 
                        point_num,
                        point_id,
                        buf_[0 + point_size * point_id], 
                        buf_[1 + point_size * point_id], 
                        buf_[2 + point_size * point_id], 
                        buf_[3 + point_size * point_id]);
            }
            data_set_flag_ = false;
        }

        now = std::chrono::system_clock::now();
        now_process_time = std::chrono::duration_cast<std::chrono::milliseconds>(now-start).count();
        process_time = (int)(process_target_time - now_process_time);

        if(process_time > 0)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(process_time));
            start = std::chrono::system_clock::now();
        }
    }
}

ここで重要なのはこれです。

        std::lock_guard<std::mutex> lock(mtx_);

上の受信関数でも呼ばれていましたが、この一行を呼ぶことでメモリの入口前の看板を確認し、退室になっていれば在室にした上でアクセスを始めます。

引数で与えている"mtx_"はグローバル変数で頭で宣言しています。

なので、これらのポイントを抑えることで簡単にマルチスレッド処理を書くことができます。

ちなみに二つターミナルを開いて、片側でudp_sub_test, もう一方でudp_pub_testを実行すると以下のように画面に出力されます。

f:id:ryo_udon:20210703132325p:plain

これでちゃんと動いていることがわかりますね。

まとめ

というわけでマルチスレッド処理をC++で書いてみました。

組み込み系をやっている人間として、処理速度に困ったとき最後の砦として存在するマルチスレッドを勉強してみましたが、意外と簡単に書けるなという印象です。

是非とも皆さんも試してみてください!!

ではでは。

/*コードブロックに言語名を表示*/ pre.code:before { content: attr(data-lang); display: inline-block; background: white; color: #666; padding: 3px; position: absolute; margin-left: -10px; margin-top: -30px; } pre.code { padding-top: 30px !important; }