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

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

【C++】 C++でマルチスレッドのクラスを作ってみたよ【マルチスレッド】【サンプル】

C++でマルチスレッドのクラスを作ってみたよ

概要

以前、C++のマルチスレッドについて説明し、サンプルを書きました。

ryo-udon.hatenadiary.jp

それ以降、業務内でマルチスレッドのアプリを作ることが頻繁にあったので、今回はマルチスレッドのみにフォーカスしたクラスを作ってみたので紹介したいと思います。

リポジトリ

リポジトリこちらになります。

cpp_test/SampleThreadが今回のサンプルプロジェクトになります。

github.com

使用方法

こちらのリポジトリをクローンしていただき、SampleThreadディレクトリ内にbuildディレクトリを作ってください。

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

cmake ..

make

これでサンプルがbinディレクトリの中に生成されるので、動かすことができます。

サンプルの内容

サンプルの内容はシンプルです。

SampleThreadクラスがメインスレッドとは別に100ms周期で動いていて、常にカウンタ(counter)を更新し、更新したカウンタを適当な変数(value)に加算し続けます。

メインスレッドも同じく100msで動いており、1秒に1回(10回に1回)この_valueを適当な数字に書き換えます。

マイループ、メインスレッドはSampleThreadクラスからcounterとvalueの値を取り出し、画面に表示すると言うプログラムです。

具体的に中身を見ていきましょう。

メイン

メインは今回testディレクトリ内に作っています。(今回作ったSampleThreadクラスの動作テストなのでtest内にしました.srcの中でも問題ありません)

main関数では頭でSampleThreadを宣言し、SampleThreadクラスのスレッドをスタート(GenerateThread())し、ループを回し始めます。

SampleThreadクラスから値を取り出すのは各種Get関数を使っています。

またSampleThreadクラスに値をセット(リセット)する際もResetValue()関数を使用します。

では次にSampleThreadクラスの中を見ていきます。

#include "thread_sample.hpp"

int main(void)
{
    SampleThread st;
    const int sleep_msec = 100;

    st.GenerateThread();
    int counter = 0;
    int value = 0;

    while(1)
    {
        counter = st.GetCounter();
        value = st.GetValue();

        printf("Counter: %d Value:%d", counter, value);

        if(counter % 10 == 0)
        {
            printf(" --> Value Reset");
            st.ResetValue(10);
        }
        printf("\n");
        
        std::this_thread::sleep_for(std::chrono::microseconds(sleep_msec));
    }

    st.CloseThread();
    return(0);
}

SampleThreadクラス

sample_thread.hpp

まずはHeaderです。

ここで必要な変数、変数の値を取り出す、セットするための関数、別スレッドで回すmain関数、mutex, threadなどを宣言しています。

#include <thread>
#include <chrono>
#include <mutex>

class SampleThread
{
private:
    std::thread _main_thread;
    std::mutex _main_mutex;

    int _counter;
    int _value;
    bool _stop_loop;

    void _StopLoop(void);
    void _Main(void);
    void _UpdateData(void);

public:
    SampleThread() : _counter(0), _value(0), _stop_loop(false)
    {

    }
    ~SampleThread() {}

    void GenerateThread(void);
    void CloseThread(void);

    int GetCounter(void);
    int GetValue(void);
    void ResetValue(const int &value);
};

sample_thread.cpp

ここでの肝はスレッドの開始、終了を行うGenerateThread(), CloseThread()関数とメモリのアクセス違反に気を遣いながら値を更新している_UpdateData(), ResetValue()関数です。

#include "sample_thread.hpp"


void SampleThread::_Main(void)
{
    const int sleep_msec = 100;
    while(!_stop_loop)
    {
        _UpdateData();
        std::this_thread::sleep_for(std::chrono::microseconds(sleep_msec));
    }
}

void SampleThread::_UpdateData(void)
{
    std::lock_guard<std::mutex> lock(_main_mutex);
    _counter++;
    _value += _counter;

    if(_counter > 100) _counter = 0;
}

void SampleThread::_StopLoop(void)
{
    _stop_loop = true;
}

void SampleThread::GenerateThread(void)
{
    _main_thread = std::thread(&SampleThread::_Main, this);
}

void SampleThread::CloseThread(void)
{
    _StopLoop();
    _main_thread.join();
}

int  SampleThread::GetCounter(void)
{
    return(_counter);
}

int SampleThread::GetValue(void)
{
    return(_value);
}

void SampleThread::ResetValue(const int &value)
{
    std::lock_guard<std::mutex> lock(_main_mutex);
    _value = value;
}

スレッドの開始/終了

まずGenerateThread()では、std::thread()を使ってこのクラスの_Main関数を別スレッドで動かすよ、と宣言しています。

逆にCloseThread()では_Main関数ないのループを終了するフラグを立てた後にjoin()関数を使って別スレッドが正常に終了するのを待っています。

join()関数で勘違いしやすいのは、この関数はあくまで"そのスレッドが終了したかを確認する"のであって"スレッドを終了させる"関数ではありません。

なのでjoinの前に止めたいスレッドの停止処理を用意してあげる必要があります。

またここでスレッドを止めないとプログラムを止めても裏でこのスレッドが回り続けてしまうので必ず呼びましょう。

void SampleThread::GenerateThread(void)
{
    _main_thread = std::thread(&SampleThread::_Main, this);
}

void SampleThread::CloseThread(void)
{
    _StopLoop();
    _main_thread.join();
}

別スレッド同士のデータの読み書き

次にデータの読み書きについてです。

以前こちらの記事で説明したように、マルチスレッドのプログラムで一番気を付けるべきはメモリのアクセス違反(segmentation fault)です。

他のスレッドが編集中のメモリに対してさらに別のスレッドが同じメモリを書き換えようとするとこのエラーが発生し、プログラムが強制的に終了してしまいます。

なのでそれを防ぐためにstd::threadと合わせて使われるのがstd::mutexです。

mutexとはメモリを書き換える際に既に他のスレッドが書き換えている場合は他のスレッドの処理が終わるのを待ちましょうと言う機能です。

このサンプルでは以下の二箇所でそれを使っています。

void SampleThread::_UpdateData(void)
{
    std::lock_guard<std::mutex> lock(_main_mutex);
    _counter++;
    _value += _counter;

    if(_counter > 100) _counter = 0;
}

void SampleThread::ResetValue(const int &value)
{
    std::lock_guard<std::mutex> lock(_main_mutex);
    _value = value;
}

上の二つの関数で共通するlock_guardが今説明したメモリへのアクセスを順番待ちする関数になります。

ただしここで気をつけたいのが、ずっとこのlockをし続けることができてしまう、と言うことです。

つまり一つのスレッドが常時メモリへのアクセスをし続けていることになり、他のスレッドがアクセスできず順番待ち=処理が止まってしまう、と言うことが起こります。

なのでmutexを使うときの鉄則として、lock_guardを呼び出す範囲は値を書き換える部分のみにしましょう。

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

最後に

と言うわけで今回マルチスレッドのクラスを作ったので紹介してみました。

今後はシングルトンのクラスや複数箇所でこのスレッドにアクセスする方法などもまとめていきたいと思います。

ではでは。

MacでC++開発環境を構築してみたよ(Part1)

MacC++環境を構築してみた Part1

概要

Macbook Airを購入したのでC++環境を構築してみました。

ここではC++のcmakeでのコンパイル開発環境整備までを書いていきます。

g++を使えるようにする。

まずはXCodeをインストールしてg++によるコンパイルができるようにします。

これはただAppStoreから引っ張ってくるだけなので簡単です。

こちらのリンクからか、あるいはAppStoreでXCodeを検索してください。

あとはインストールするのみです。

その後新しくターミナルを立ち上げg++コマンドが呼び出せるようになっているか確認してください。

合わせてmakeコマンドも入っているはずです。

cmakeを使えるようにする。

次にcmakeを使えるようにします。

cmakeとは何かについてはこちらのサイトなどがわかりやすいので参考にしてください。

平たく言うとコンパイル時にどのような手順でコンパイルしていくか(依存関係)やそのコンパイルの各種設定を自動でしてくれるビルド自動化ツールです。

なのでソースコード1つだけの時はほとんど恩恵を受けることはありませんが、ソフトの規模が大きくなればなるほどその恩恵は大きくなります。

特に個人的に嬉しいのがCMakeLists.txtで色々なところへパスを簡単に通せるので、作成した機能の役割ごとにディレクトリを分けるなどよりコードの可読性をあげ、他のプロジェクトに移植しやすかったりすることです。

なので自然とライブラリチックに単一機能に絞って書くことが習慣付くので自分は気に入っています。

cmakeのインストール

homebrewインストール

インストールにはhomebrewを使います。

homebrewのインストール方法はこちらの記事をご確認ください。

ryo-udon.hatenadiary.jp

cmakeをインストールする

特に難しいことはありません。

brew install cmake

これだけです。

あとはターミナルを開き直してもらえればcmakeコマンドが出ていることがわかるかと思います。

cmakeの使い方

CMakeLists.txt

下に自分がよく使うCMakeLists.txtを掲載します。

このCMakeListsが設定しているのは以下の項目です。

  • C++コンパイル時設定
  • 実行ファイルの出力先(存在しない場合は自動的に生成)
  • ライブラリの出力先(存在しない場合は自動的に生成)
  • includeで参照するパスの指定
  • 使用するライブラリがあるパスの指定
  • コンパイルしたい実行ファイルに必要なソースコードを指定
  • コンパイルしたい実行ファイルに必要なライブラリを指定
# Cmake version
cmake_minimum_required(VERSION 3.5)

# Project Name and Language
project(thread_sample CXX)

set(CMAKE_CXX_FLAGS "-g -O0 -Wall -pthread -std=c++11")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)

# Add Subdirectory
#add_subdirectory(src)

# Add Include dir
#target_include_directories(
#  new_object_detection
#  ${PROJECT_SOURCE_DIR}/include
#)

include_directories(
    ${PROJECT_SOURCE_DIR}/include
    )

link_directories(
    ${PROJECT_SOURCE_DIR}/lib
)

add_library(thread_sample STATIC src/thread_sample.cpp)
target_link_libraries(thread_sample)

add_executable(thread_test test/thread_test.cpp
)
target_link_libraries( thread_test
        thread_sample

)

cmakeの実行場所

個人的にcmake, makeはコンパイルしたいプロジェクト内にbuildディレクトリを作成し、その中で実行することをオススメします。

この理由はコンパイル時に生成される途中経過ファイルが全てbuildファイルの中に保存されるため、他のディレクトリを汚さないことなどが挙げられます。

なのでまずbuildディレクトリを作成し、ターミナルでbuild内に移動した後、

cmake ..

を実行してください。

するとbuildの中にMakefileが生成されます。これでmakeができるようになります。

make

同じくbuildの中でmakeを実行してもらえれば、自分で指定した実行ファイルやライブラリがbinやlibの中に生成されます。

実践

ここでは自分がサンプルで作ったマルチスレッドクラスのThreadSampleを参考に実際に使ってみます。

今回使用するリポジトリこちらです。

github.com

今回はこのcpp_testerの中にあるThreadSampleを例にcmake, makeを使っていきます。

git clone

まずはこちらのレポジトリをローカル(自分の手元のパソコン)にclone(ダウンロード)してきます。

保存したいディレクトリにターミナルで移動して以下のコマンドを実行いただくか、下の画像にあるDownload zipからzipファイルでダウンロードしてください。

git clone https://github.com/RYO0115/cpp_tester.git

buildディレクトリを作る

次にcpp_tester/ThreadSampleの中にbuildディレクトリを作成し、ターミナルでその中に移動します。

cmake

ここで実際にcmakeを実行します。

次のコマンドを実行してください。

cmake ..

ここでcmakeの後の".."はCMakeLists.txtの場所になります。

もしbuildディレクトリの中にCMakeLists.txtがある場合は、このコマンドは"cmake ."になります。

ただ基本的にCMakeLists.txtとcmakeを実行する場所は分けることをオススメします。

それは上にもちらっと書きましたが、cmake, makeの中間ファイルが全てコマンドを実行した場所に保存されるからです。(CMakeLists.txtで保存場所を変更すればその限りではありませんが)

なので基本的には分けておいた方が無難でしょう。

make

cmakeを実行したことでbuildの中を覗くとMakefileが生成されているかと思います。

これでコンパイルの準備が完了です。

実際にmakeしてみましょう。build内で以下のコマンドを実行してください。

make

これでsrc,test内のソースコードコンパイルされます。

ファイルの確認

最後に今回のcmake, makeで出来上がったものを確認します。

thread_testが実行ファイル、libthread_sample.aが今回静的ライブラリ化したファイルになります。

他のソースコードでThreadSampleクラスを使いたい場合は、includeの中にあるthread_sample.hppとこのlibthread_sample.aへパスを通せば使えるようになります。

最後に

と言うわけでC++コンパイルができる環境構築と実行方法をまとめました。

CMakeLists.txtは上で書いたものの数倍数十倍の機能があるので、必要に応じてどんどんいじってください。

ではでは。

【ChromeCast】画面シェア機能 ChromeCastはどの環境で使えるのか?【Windows】【Mac】【Android】【iOS】

画面シェア機能 ChromeCastはどの環境で使えるのか?

概要

最近自分の周りでどうやって手元のデバイスの映像をテレビに飛ばせばいいのか(しかも音声付で)、ということで議論が沸き起こっています。 (その火種になったのは自分の可能性が大いにありますが)

そもそもテレビに何かキャストしたいとあまり思わない人間なので今までスルーしてきましたが、今自分の手元を見ると、

と、比較検証すべきデバイスがすべてそろっていることに気づきました。

というわけで今回はどのデバイスであればテレビに快適に映像が映せるのかを確認してみました。

なお、ここでは自分が頻繁に使用するSpotv Nowのサッカー映像をもとに検証していきます。

実験環境 (キャスト先)

大層なタイトルですが、今回キャスト先として2017年6月発売SONYKJ-43X8000Eという5年以上前のAndoroid TVを使用しています。

4K対応テレビですが世代がかなり前なので、ここ最近でテレビを買い替えた方であれば恐らくこのテレビよりも高いスペックになっているかと思うのでベンチマークとしては悪くない対抗機だと思います。

もちろんこちらのテレビはネットワークに接続しています。

ネットワークへの接続設定については、各メーカーごとに違いますので各自のテレビメーカーから確認して下さい。("メーカー名 型番 ネットワーク 接続方法" とググれば大体でてきます)

比較内容

概要で説明した通り、Spotv Nowで見られるサッカーのフル動画を試しに5分ずつ視聴しています。

ライブ映像だとフル動画よりもよりラグや読み込みなどが入る可能性がありますので、あくまで参考値です。

またChromeCastはGoogleの機能なのでブラウザは全てGoogle Chromeで確認しています。

接続方法(キャストのやり方)

PC (Windows, Mac)

キャストの方法は簡単です。 まずは開きたいページをGoogle Chromeで開きます。

その後画面右上のメニューボタンからキャストを選択してください。

するとしたのように接続可能なデバイスが一覧になって出てきます。

後は接続したいデバイスをクリックすればテレビに接続されます。

(デスクトップは写真を撮ったのですが、あまりにハーネスが汚いので掲載しません)

Windows ノートPC

Macbook Air

Android

AndroidWindows PCよりももっと簡単です。

画面上からスライドさせて表示するメニュー画面に画面のキャストというボタンがあります。

こちらをタップしていただき、キャスト先のデバイスを選択するだけです。

iOS

残念ながらiOS単体ではChromeCastはできませんでした。

iOSバイスをお持ちの方は下にあるようなChromeCastデバイスを購入し、テレビに差し込む必要があります。

ただし、こちらはミラーリングにしか対応していなさそうなので、もしかしたら映像は出るけど音声は出ない、ということになるかもしれません。

参考記事

テスト結果

バイス 有線/無線 映像 音声 映像の安定性 手軽さ
Windows PC (デスクトップ) 有線
Windows PC (ノート) 無線 ◎?
MacBook (ノート) 無線 ◎?
Android 無線
iOS 無線 × -

結果としてはパソコンは全て安定して映像をテレビにキャストすることができました。

意外にも無線で繋いだノートPCでも安定して映像を映すことができました。(これは結構ありがたい)

テレビで見るときはソファなど少し離れたところで寛ぎながら見る人が多いかと思いますので、これはうれしい結果です。

それに対しAndroidはライブ映像ではないにも関わらずブツブツと映像、音声が途切れるのが気になりました。

そして一番残念なのはiPadだとそもそもChrome Castできませんでした。

一応ミラーリングまでは怪しいアプリを使えばできますが、いろいろとリスクもありそうなのでお勧めはしません。なので手軽さは評価無しとしました。

実際使う際はライブ映像なので、無線での映像の安定性についてはまだ懸念が残っているので今後試した際にまたアップデートしたいと思います。

最後に

というわけで、今回いくつかのデバイスでChromeCastを使って映像を音声付でテレビに映すことができるのかを試してみました。

自分としてはMacbookから簡単に映せるのは個人的に驚き&ありがたい結果なので、今後は活用していこうと思います。

少しでもこちらの内容がためになれば幸いです。

ではでは。

2023年 MacBook Air 開発環境構築

MacBook Air 開発環境構築

概要

今回はPythonとTypescriptの開発環境を入れていきます。

また追々C++環境もApple clangのものではなくgccのg++を使えるようにしたいと思っています。

Homebrew Install

Mac環境に数々のツールを入れるための必須ツールであるパッケージ管理ツールHomebrewをインストールしていきます。

インストールは簡単です。

まずはターミナルを開き、以下のコマンドを順番に実行していきます。

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"


(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> /Users/ryota_amano/.zprofile

eval "$(/opt/homebrew/bin/brew shellenv)"

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

Git

インストール

次にコード管理のためにGitをinstallしていきます。

ここではHomebrewからインストールします。

brew install git

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

ユーザ名、アドレスの設定

次にGitでコミットするために必要なユーザ名とメールアドレスを設定します。

git config --global user.name "ユーザ名"
git config --global user.email "メールアドレス"

これでコミットなどのGit機能が使えるようになります。

C++環境構築

長くなったので別記事としました。

ryo-udon.hatenadiary.jp

Python3.9以降 環境構築 (pyenv + pipenv環境構築)

以前WSLで構築したpyenv + pipenv環境を構築していきます。

M2 Macbook AirなのでPython3.9以降を想定した環境を構築していきます。

pyenvインストール

pyenvもHomebrewでインストールしていきます。

brew install pyenv

これでpyenvがインストールされたので、次にPythonのバージョンを指定してインストールしていきます。

まずはインストール可能なバージョンを確認します。

pyenv install -l

これでインストール可能なバージョンがリストで表示されます。

今回は一番最新の3.11.4をインストールしていきます。

pyenv install 3.11.4

しかしここで問題が、

下のようにlzmaというライブラリがないですよ、とwarningがでます。

一度pyenvでインストールしたpython 3.11.4をuninstallします。

pyenv uninstall 3.11.4

綺麗な状態で足りないライブラリと設定をしていきます。

brew install openssl readline sqlite3 xz zlib tcl-tk

これで再度pyenv installを試していきます。

pyenv install 3.11.4

これで無事にインストールできました。

pyenv 適用

自分はどのディレクトリでもこの3.11.4をベースに動いて欲しいので以下のコマンドを実行しました。

pyenv global 3.11.4

もし特定のディレクトリでのみ動いて欲しいのであれば、そのディレクトリに移動した後に以下のコマンドを実行してください。

pyenv local 3.11.4

次にルートディレクトリにある ~/.zshrcファイルに以下の設定を追加します。

export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

その後この設定ファイルを再度読み込むためにターミナルを再起動する or 以下のコマンドを叩いてください

source ~/.zshrc

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

pipenvインストール

Pythonの仮想環境を作成するためにpipenvをインストールしていきます。

pipenvのインストールは先ほどpyenvでインストールした中に入っているpipを使ってインストールします。

pip install pipenv

pipenvを使った環境構築

pipenvの使い方についてはこちらの記事を参考にして下さい。

TypeScript/JavaScript環境構築

ここではTypeScript/JavaScriptの開発環境を構築するために以下の各種ライブラリ等をインストールしていきます。

  • nodebrew
    • Node.jsのバージョン管理ツール
  • Node.js
    • JavaScriptアプリを作る強い味方. さまざまな機能がライブラリ化されてます。

nodebrew/Node.jsのインストール

公式のインストーラもありますが、ここもHomebrewでインストールしていきます。

brew install nodebrew

次にnodebrewの設定をします。

nodebrew setup

これで必要な設定が$HOME/.nodebrew/に生成されます。

これを.zshrcにもパスを書いていきます

下の一文を~/.zshrcに追加してください。

export PATH=$HOME/.nodebrew/current/bin:$PATH

またまた設定を反映するためにターミナルを再起動 or 以下のコマンドで反映してください。

source ~/.zshrc

その後最後にnodebrewインストール後に最新版のNode.jsをインストールします。

nodebrew install-binary latest

念の為、インストールしたNode.jsのバージョンを確認しましょう。

node -v

これでバージョン情報が表示されたらインストール成功です。

TypeScriptのコンパイラインストール

Node.jsをインストールするとnpmというJavaScriptのライブラリ管理ツールもインストールされます。

こちらを使ってコンパイラをインストールしていきます。

npm install -g ts-node
npm install -g typescript

最後にコンパイラのバージョンを確認してインストールできているかを確認します。

tsc -v

これでバージョンが表示されればコンパイラのインストール完了です。

Prettier(コード整形ツール)インストール

まずはパッケージ管理ツールのyarnをインストールします。

npm install -g yarn

このyarnを使ってPrettierをインストールします。

yarn add -D 'prettier@^2'

ESLint(コーディング規約チェックツール)インストール

コーディング規約に準拠しているかを自動で確認してくれるESLintをインストールします。

yarn add -D 'eslint@^8'

Better Touch Toolsを使ってMacBook Airをカスタムしたよ[トラックパッド][カスタム]

Better Touch Toolsをつかったトラックパッドのカスタムを紹介するよ

概要

MacBookを買う理由の50%以上を占める(と勝手に思っている)トラックパッドを拡張していきます。

ここで使うのはBetter Touch Toolです。

こちらはトラックパッド上の操作を指の本数からタップする位置までを区別して、それにさまざまな機能を割り当てることができるツールです。

今回はこのアプリを使って拡張していきます。

ちなみに10年ほど前は無料だったのですが、MacユーザーをBTT漬けにして逃れられなくなったところで有料化されました。(2年で$10, 買い切りで$22です)

今回の設定の多くはこちらを使うので、ここは諦めて課金しましょう。

Better Touch Toolsでの設定追加方法

Better Touch Toolへの設定追加は以下のようにします。

今回はトラックパッドの設定を例に説明します。

まずはウィンドウの上方真ん中にあるプルダウンをクリックして、"トラックパッド"を選択します。

するとこういう画面が出てきますので真ん中にあるプラスボタンを押します。

するとどういう入力をした際の設定をしますか、ということで最初にTriggerを聞かれます。

(下の画像ではデフォルトの状態を見せるためにあえてmagic mouseの画面を貼り付けています)

試しに一本の指でタップを押すと次のような画像のようになります。

今度は横に出てきたプラスボタンを押してもらうとそのtrigger(操作)した時、どういう操作をするのかを設定します。

プルダウンを見てもらうとキーボードショートカットを始めmacの機能、スペース/デスクトップの移動などさまざまな機能を割り当てられます。

では今回自分が割り当てた機能を便利度の高いものから順番に紹介していきます。

BetterTouchToolsでの設定前に

トラックパッドのデフォルト設定の一部を無効化(一部デフォルトで無効にされている機能を有効化)

今回、デフォルトで設定されているジェスチャーに別の機能を割り当てるので先に無効化します。

こちらもシステム設定からトラックパッドを開きます。

その他のジェスチャに移動して以下のように設定してもらいます。

画像

おすすめ設定

タブ移動 (3本指左右スワイプ)

ブラウザで複数のタブを開いているとき別のタブに移動したい時がありますよね?皆さんはどうしていますか?

おそらくほとんどの人はマウスカーソルを移動させてクリックしていると思います。

もしくはCommand + tabで切り替えるというレアな方もいるかもしれません。

その作業、トラックパッドでやりませんか?

ということでBetter Touch Toolで早速割り振っていきます。

昔から三本指で左右にスワイプを割り当てていたので今回もそれを割り振っていきます。

こちらはMacの使い心地に合わせるために動作は スワイプの方向と反対に移動するように設定しています。

設定内容としては、triggerは"3本指で左(右)にスワイプ"を選択し、アクションは"キーボードショートカット"で"Control + Tab (右の場合はControl + Shift + Tab)"を設定します。

これでマウスカーソルを動かさずに3本指で左右にスワイプするだけで、ブラウザのタブを移動できます。

(VSCodeソースコード間の移動もできます!!)

これでネットサーフィンの効率は相当効率化されます!!

新しいタブ作成 (1本指でトラックパッドの左下をタップ)

ブラウザで新しいタブを作りたいとき、一々カーソルを右上に持っていくのはめんどくさくないですか?

そのめんどくさい作業、トラックパッドに割り当てましょう。

ということでこちらもBetter Touch Toolで割り当てていきます。

triggerで"1本の指で左下をタップ"を選択し、アクションでこれまた"キーボードショートカット"で"Command + T"を設定してください。

これでブラウジング中に左下をタップすると新しいタブがひらけます。

ページを閉じる (四本指クリックで開いているタブやウィンドウを閉じる)

ネットサーフィンをしている時に煩わしく感じることの一つに見終わったタブを閉じる作業です。

これもトラックパッドに割り当てちゃいます。

triggerで"4本の指でクリック"を選択し、アクションでこれまた"キーボードショートカット"で"Command + W"を設定してください。

これでブラウジング中に4本指クリックでタブ、ウィンドウを閉じることができます。

こちら昔は3本指が多かったのですが、新しいトラックパッドは感度が上がったのか、タブ移動の際に誤爆が多かったので4本に変更しました。

ブラウザページの更新 (1本指でトラックパッドの右下をタップ)

新しいタブ作成とほぼ同じです。

triggerで"1本の指で右下をタップ"を選択し、アクションでこれまた"キーボードショートカット"で"Command + R"を設定してください。

これでブラウザで見ているページを手軽に更新できます。

デスクトップの移動 (4本指でスワイプしてデスクトップを移動する)

Macのデフォルト設定でも移動できますが、3本指のスワイプをタブ移動に割り当てたのでこれを4本に当てます。

triggerで"4本の指で左(右)にスワイプ"を選択し、アクションで"スペース/デスクトップ間の移動"から"スペースを右(左)に移動"を設定してください。

単語を辞書で調べる (3本指でタップして単語を辞書で調べる)

Macを使う際に意外と便利な機能がこの単語検索機能です。

自分は英語の記事や論文を読むことが度々あるので、この機能は重宝しています。

どういう機能かというと、例えばブラウザで分からない英単語があれば、こんな感じでその場で単語の意味を教えてくれるのです。

デフォルトでもトラックパッドから起動できるのですが、1本指の長押しと少し使い勝手が微妙です。なので今回は空いている三本指のタップにこの機能を割り当てていきます。

triggerで"3本の指でタップ"を選択し、アクションで"macOS機能"から"カーソル下の探索語"を設定してください。

最後に

トラックパッドのカスタムは奥が深いです。

またいい設定を見つけたらまた追記していきたいと思います。

WSL2 + Dockerを公式インストーラでインストールしてみた際にはまったこと

WSL2 + Dockerインストール

概要

新しく構築したWSL2 Ubuntu 22.04にDocker環境を構築するために過去の自分の記事をもとにインストールしようとしたらかなり古新聞になっているようでした。

なのでここでは公式インストーラでインストールをしつつ、一部設定をいじる必要があったのでその部分に言及した短い記事にしようと思います。

Docker インストーラ

まず公式サイトからGet Startedをクリックし、

Windowsを指定してダウンロードします。

このインストーラがWSLに対応しているので、気にせずダウンロードし、実行してください。

画像を取り忘れてしまったので恐縮ですが、実行後は何も設定をいじらずインストールを押して数分待てばインストールできます。

もしapt installなどでDocker関係を入れてしまっている人は

sudo apt remove docker*

でアンインストールすればインストーラから改めてDockerを入れなおすことができます。

インストールが完了するとサインアウトを求められるのでサインアウトします。

設定変更

さて、ここまですればほぼ準備は万端、といいたいのですが、CLI(コマンド)からDockerを使用するには設定をする必要があります。

(私はここにはまりました)

この設定をせずにDockerコマンドを使おうとすると、そんなコマンドないよと怒られます。

なので、Docker Desktopを実行し、設定していきます。

右上の設定ボタンを押し、Resources --> WSL integrationを選択し下の画面を表示します。

後はWSLで使用しているUbutnuバージョンをONにして右下の「Apply & restart」をクリックすれば設定完了です。

(Apply & restartのボタンは何だか感度が悪いので連打しなくても大丈夫です)

最後に

今回はかなり短い記事ですが、公式インストーラを入れて少し悩んだので備忘録として追記しました。

他にはまりポイントなどあればここか別記事で足していきたいと思います。

ではでは。

【VSCode】WSL2 + VSCode + pyenv + pipenv 環境を自分なりに構築してみた 【pipenv】

WSL + VSCode + pyenv + pipenv 環境を自分なりに構築してみた(しなおしてみた)

久しぶりに余裕ができたので自分のパソコンで最近はやりのOpenAIのAPIでも叩いてみようかと思っていたら、

「あれ?Python動かねえ。。。?」

結論から言うとWSLで起動するUbuntuバージョンが違うだけだったのですが、せっかくなのでWSLのUbuntuを22.04にして、python環境を構築しなおしてみました。

また、これまで避けてきたpipenv環境を構築し、vscodeで起動時にPIPENV_VENV_IN_PROJECTを自動的に設定するところまでやってみました。

では、やっていきましょう。

WSL環境の構築, pyenvのインストールについて

WSL環境の構築, pyenvのインストールについては、すでに過去に幾つか記事を書いていますので、そちらを参照ください。

WSL環境の構築はこちらの記事で詳細に説明しています。

ryo-udon.hatenadiary.jp

pyenvのインストールは以下の記事の後半で説明しています。

ryo-udon.hatenadiary.jp

こちらの記事ではwindowsにすでにpython環境を作成済みの方のお悩み解決になるかと思います。

今回実際に構築した環境+プロジェクト

こちらリポジトリになります。

pipenvが関係するのは、このルートディレクトリにいるPipfile, Pipfile.lockになります。

注意書き

ここから先はpyenvでpython 3.11.3を起動した、という前提で説明していきます。

なので、コマンドとしては以下が行われた状態で実行していきます。

pyenv install 3.11.3
pyenv global 3.11.3

Pipenv

pipenvのインストール

installはpipを使います。

pip install pipenv

これだけでpipenvがインストールされます。

pipenvの初期化

まずpythonのバージョンに併せてpipenvを初期化します。

私は今回Python3.11.3で環境を作ったので、以下のコマンドを実行します。

pipenv --python 3.11

このコマンドを実行するとPipfileというファイルが自動作成されます。

Pipfileは、その開発環境にどんなパッケージがどのバージョンでインストールされているかを管理しています。

例えば上のレポジトリのPipfileを見ると

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
numpy = "*"
matplotlib = "*"
openai = "*"
ipykernel = "*"
python-dotenv = "*"

[dev-packages]
ipykernel = "*"

[requires]
python_version = "3.11"
python_full_version = "3.11.3"

基本的にこのファイルを手動で操作することはありません

なので、コミットの際に忘れずこちらのPipfile, Pipfile.lockを含めれば、この次に紹介するコマンドで簡単に開発環境を再構築することができます。

pipenvでのパッケージ(ライブラリ)インストール

新しくパッケージを追加する場合

新しくパッケージをインストールする場合、pip installの代わりにpipenv installを使用します。

pipenv install numpy

このコマンドを実行すると、指定したパッケージがインストールされるだけではなく、このPipfileの[packages]の部分に追記されます。

開発用パッケージとしてinstallしたい場合は

pipenv install --dev ipykernel

のようにして区別してインストールできます。

新しくパッケージをバージョンを指定して追加する場合

パッケージのバージョンを指定してインストールすることもできます。

pipenv install "pandas==0.15.0"

ただし公式サイトを参照すると、この指定方法だとpipenvがアップデートしなくなる、ということから

pipenv install "pandas~=0.15.0"

を推奨しているようです。

またこのバージョン以上、という指定であれば、

pipenv install "pandas>=0.15.0"

バージョン以下であれば、

pipenv install "pandas<=0.15.0"

このバージョンより上、であれば、

pipenv install "pandas>0.15.0"

となります。

Pipfileから環境再現(指定されたパッケージを最新バージョンでインストール)

こちらのPipfileから環境再現ももちろんできます。

pipenv install

もし開発用パッケージもインストールする場合

pipenv install --dev

上の例として上げたレポジトリの場合は後者のコマンドを実行することになります。

これらのコマンドを実行することで、必要なパッケージの最新バージョンがインストールされます。

Pipfileから環境再現(指定されたパッケージを実際に使用していたバージョンでインストール)

まったく同じ開発環境を構築したいと思うと、それぞれのパッケージのバージョンまで合わせる必要があります。

その場合はPipfileではなくPipfile.lockが使用されます。

Pipfile.lockは各パッケージのバージョン情報を保持しているので、こちらを使うとまったく同じ環境を再現することができます。

pipenv sync

pipenv installと同じく、開発用パッケージもある場合は

pipenv sync --dev

でまったく同じ環境が再現できます。

requirements.txtからインストール

pipを使い慣れている方ならお馴染みのrequirements.txtを使ってまとめてインストールすることも可能です。

まずはコマンド

pipenv install -r requirements.txt

次にrequirements.txtの書き方ですが、こちらも従来と同じです。

numpy
matplotlib
pandas

VSCodeでのkernel選択

ここから正攻法でのkernel設定方法を説明します。

手元のpath設定の状況によって、こちらでも簡単に設定できる方がいるかもしれません。

ただできない方も多いかと思うので、そのような方はこの章を読み飛ばして、次のVSCodeでのkernel選択(裏技)を参照ください。

Pythonスクリプト

Pythonスクリプトを実行する場合は、画面右下から設定します。

画像の部分をクリックすると下のようなkernelのリストが追加されます。

右側にそれがpyenvなのか、pipenvなのか、など書いてくれていますので、pipenvのものを選びましょう。

この表で一番上に表示されているRecommendedについては、今回の記事の一番の工夫ポイントになりますので、後の章で説明します。

Jupyter Notebook

Jupyter Notebookの場合は画面右上から設定します。

画像の部分をクリックすると下のようなkernelのリストが追加されますので、この中から探してください。

もしkernelが見つからない場合

ここに指定したいkernelが出てくればいいですが、もし出てこない場合は、以下の手順でパスを通してください。

Pythonスクリプトの場合

こちらの表の一番上のEnter interpreter path -> Findから使いたい仮想(pipenv)環境のpython.exeを選択してください。

Jupyter Notebookの場合

一番下のSelect Another Kernel -> Python Environments と進みます。

その後、Python環境のリストが出てきますが、この中でも出てこない場合は一番上のCreate Python Environmentへ進みます

Create Python Environment -> Venv -> Enter interpreter path

から、実行したい仮想環境のbinに入っているpython.exeを指定してください。

VSCodeでのkernel選択(裏技)

裏技と書いていますが、実際は以下のことをしているだけです。

  • pipenvの仮想環境をプロジェクトのローカルに保存するように変更 (./.venv に移動)
  • パッケージをローカルの.venv内に保存
  • VSCode setting.jsonで以下の二つを設定する
    • ローカルに仮想環境を保存するコマンドを自動実行
    • 使用するpython環境をローカルの仮想環境に設定

ただし、これだと新しく環境を構築する度に環境変数をいじいじする必要があるため、ヒューマンエラーが出てしまいます。

そこで、最初の環境変数vscodeのsetting.jsonに埋め込むことで、ほぼ設定なしで環境を再構築できるようにします。

順番に説明した後、最後にどうやって使うのかを説明していきます。

pipenvの仮想環境保存場所をプロジェクトのローカルに変更

pipenvの仮想環境をローカルに保存するのは実は簡単です。

PIPENV_VENV_IN_PROJECT という環境変数があり、これをtrueにするだけで、ローカルに.venvディレクトリを作成し、そこに各種プロジェクトを保存するようになります。

(もちろんpython.exeなども保存されます)

今回はこのコマンドを叩くことはありませんが、

export PIPENV_VENV_IN_PROJECT=true

を実行した後にpipenv installすればローカルに保存されるようになります。

pipenvのプロジェクトをローカルに保存

こちらは上にも説明したinstallコマンドで実行可能です

PIPENV_VENV_IN_PROJECT=trueの状態で。

pipenv install

または

pipenv install --dev

を実行すれば、これでPipfileをもとにローカルにインストールしてくれます。

VSCodeのsetting.jsonを設定する

次にVSCodeの設定を行います。

下で二つ設定をしますが、設定が完了したら念のためVSCodeを一度再起動してください。

VSCodeでPIPENV_VENV_IN_PROJECTを自動設定する

VSCodeユーザーの方であればご存じかと思いますが、VSCodeにはsettings.jsonというファイルが存在します。

このファイルは多種多様に渡るVSCodeの機能、その設定ファイルになります。

そしてこのファイルはdefault, user, そしてworkspaceで分けて設定することが可能です。

今回はworkspaceの中に生成されるsettings.jsonを使って、上のpipenv環境を自動で設定できるようにしていきます。

Ctrl + Shift + P のショートカットで機能一覧を開き、"settings json"で検索すると以下のように何項目かでてきます。

ここでWorkspace Settingsを開きます。

最初は恐らく下のような何も書かれていない状態だと思いますが、ここに以下の二つを追加します。

初期状態:

{

}

編集後:

{
    "terminal.integrated.env.windows": {
        "PIPENV_VENV_IN_PROJECT": "true"
    },
    
    "terminal.integrated.env.linux": {
        "PIPENV_VENV_IN_PROJECT": "true"
    },
}

ここではWindows, Linux両方で設定しています。

上を追記したら保存してください。

Python Kernelの自動設定

Python Kernelも同じくsettings.jsonで設定します。

追加する内容はシンプルです。

ローカルで保存するようにしたpipenv仮想環境へのパスを記述するだけです。

なので以下のように三行追記します。

{
    "terminal.integrated.env.windows": {
        "PATH": "${workspaceFolder}/.venv/bin;${env:PATH}",
        "PIPENV_VENV_IN_PROJECT": "true"
    },
    
    "terminal.integrated.env.linux": {
        "PATH": "${workspaceFolder}/.venv/bin;${env:PATH}",
        "PIPENV_VENV_IN_PROJECT": "true"
    },

    "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python.exe",
}

これで保存したら設定は完了です。

次に実際に使い方を説明します。

サンプルレポジトリを例とした使い方

サンプルレポジトリをもとに説明していきます。

ちなみに前半はgit, pipenvが使えるターミナルであればなんでも大丈夫です。

もしVSCodeのターミナルで実行する場合は、後で一度VSCodeを開き直す必要がありますのでご注意ください。

リポジトリをクローン

まずこちらのレポジトリをクローンしてきます。

適当なディレクトリで

git clone https://github.com/RYO0115/chatgpt_prompt_engineering.git

クローンしたディレクトリに仮想環境を保存

クローンできたら、chatgpt_prompt_engineeringのディレクトリへ移動し、仮想環境を保存していきます。

コマンドは以下の1つだけで大丈夫です。(すごく便利!!)

pipenv install --dev

今回 ipykernelも入れるので--devコマンドをつけています。

(VSCodeで実行している場合)VSCode 再起動

ここで一度VSCodeを再起動します。

再起動と言っても、そのプロジェクトを開いているウィンドウを一度閉じて開きなおすだけです。

再度プロジェクトをVSCodeで開き、Jupyter Notebookを開く

VSCodeでプロジェクトを開き、guidelines.ipynbを開いて見てください。

すると右上のkernelの部分がdetectingとなった後に.venvに設定されます。

これでpipenv環境との紐づけは完了です。

終わりに

というわけで、今回はWSL2 + Windows11 + pyenv + pipenv + VSCode環境構築とそれを簡単に管理する方法について紹介しました。

まだpipenvについては研究する余地があるかと思いますので、今後も更新していきたいと思います。

また、何かほかにこうした方がいいなどのアドバイス、コメントあればお願いします。

ではでは

参考

Pipenvを使ったPython開発まとめ 【図解】作業が倍速!pipenvの使い方【Python】

/*コードブロックに言語名を表示*/ 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; }