web-technical-blog

web開発に関する技術メモ

VSCでJupyterが使用できるということで試してみた

動作環境

  • windows10

設定したこと

python -m pip install jupyter
python -m pip install matplotlib
#%%
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

x = np.linspace(0, 20, 100)
plt.plot(x, np.sin(x))
plt.show() 

結果

f:id:yoshitachi:20181112142144p:plain

参考URL

https://news.mynavi.jp/article/20181109-721502/

(Python)並行処理と並列処理について

並行・並列

  • 並行は英語でConcurrent、並列はParallelと表現される
  • 並行と並列は別ものである by RobPike

並行(Concurrent)

  • 複数のスレッドを使って処理を走らせる
  • スレッドは共有のメモリ領域を利用する
  • 同時にいつくかの質の異なることを扱う
    • (例) 本を積む、本を運ぶ、本を燃やす、台車を戻す

並列(Parallel or Parallelism)

  • 複数のプロセスを使った処理
  • プロセスは専用のメモリ領域を利用する
  • 同時にいくつかの質の同じことを扱う
    • (例) 本を燃やす、本を燃やす、本を燃やす

f:id:yoshitachi:20181112114605p:plain f:id:yoshitachi:20181112114222p:plain

複数のスレッドを使った処理をする場合、同一のプロセス内でスレッドが切り替わりながら処理が進む。

Apacheの設定にあるpreforkとworkerは、プロセス、スレッドのとぢらで動かすかの違い

複数のプロセスを使って処理をする場合 - コアが1つだけのCPUであれば、やはりプロセスを切り替えながら処理が進むが - コアが複数であったり、CPU自体が複数ある場合は、1つのコアに1つのプロセスが処理できるため、同時的に処理が進む

ライス、みそ汁、焼き魚の定食を作るとすると

  • 1人の人間が進める場合

    • 湯を沸かしている間に炊飯器をセットし、魚をやくためのグリルを温める...というように
    • 作業を切り替えながら同時進行させていくのが並行処理に相当する
  • 3人の人間が進める場合

    • それぞれの品を担当して同時進行させていくのが並列処理に相当する

1人の人間が作業を切り替えながら料理を進行していくのは3人で進める場合に比べて忙しそうだがすべて自分好みの味にできる。 これは処理対象の情報を自分の中で共有できているから。

pythonではmultithread,multiprocess,asyncioを使ったプログラミングでは細やかな多重処理の制御が行えるが、 そもそも並列処理プログラミング自体がなかなか複雑になりやすい面もある

Pythonで比較的扱いやすいライブラリであるconcurrent.Futureを使ってみる

concurrent.Futureライブラリについて

Futureとは他の言語やライブラリではpromise,delayなどとも呼ばれ、 ある処理の結果が後で取得されることを前提に処理の実装が行えるようにするもの

並列処理をマルチスレッドで行いたい場合

  • ThreadPoolExecutorメソッドを使用する
    • スレッドを使って並列タスクを実行する
    • ネットワークアクセスなどCPUに負荷がかからない処理の並列実行に適している

マルチプロセスで行いたい場合

  • ProcessPoolExcutorメソッドを使用する
    • プロセスを使って並列タスクを実行する
    • CPUに負荷がかかる計算処理などの並列実行に適している

必要なライブラリ

pip install futures
pip install requests
"""
音楽ファイルの並列ダウンロード
"""
import concurrent.futures
from os import path
from urllib import parse
import requests
import mylogger
import shutil

# ログ設定
logger = mylogger.get_my_logger(__name__)

MUSIC_URLS = ['https://archive.org/download/ThePianoMusicOfMauriceRavel/01PavanePourUneInfanteDfuntePourPianoMr19.mp3',
              'https://archive.org/download/ThePianoMusicOfMauriceRavel/02JeuxDeauPourPianoMr30.mp3',
              'https://archive.org/download/ThePianoMusicOfMauriceRavel/03SonatinePourPianoMr40-Modr.mp3',
              'https://archive.org/download/ThePianoMusicOfMauriceRavel/04MouvementDeMenuet.mp3',
              'https://archive.org/download/ThePianoMusicOfMauriceRavel/05Anim.mp3']

def download(url, timeout=180):
    # mp3のファイル名をURLから取り出す
    parse_url = parse.urlparse(url)
    file_name = path.basename(parse_url.path)

    # ダウンロード開始をログ出力
    logger.info("[download start] {file_name}".format(file_name=file_name))

    # 音楽ファイルのダウンロード
    r = requests.get(url,timeout=timeout)

    # ダウンロードの終了ログをログ出力する
    logger.info("[download finished] {file_name}".format(file_name=file_name))

    with open(file_name, "wb") as file:
        shutil.copyfileobj(r.raw, file)

    return

if __name__ == '__main__':
    # 同時に2つの処理を並行実行するためのexecutorを作成
    with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
    ##with concurrent.futures.ProcessPoolExecutor(max_workers=2) as executor:
        logger.info("[main start]")

        # executor.submit()によりdownload関数を並行実行する。download関数の引数にmusic_urlを与えている
        # 並行実行処理のまとまりを futures 変数に入れておく
        futures = [executor.submit(download, music_url) for music_url in MUSIC_URLS]

        # download()関数の処理が完了したものから future 変数に格納する
        for future in concurrent.futures.as_completed(futures):
            # download関数の実行結果を resultメソッドで取り出す
            music = future.result()

        logger.info("[main finished]")
"""
loggerは別パッケージ
"""
import logging
from logging import getLogger, StreamHandler, Formatter

def get_my_logger(name):
    # loggerオブジェクトの宣言
    logger = getLogger(name)

    # loggerのログレベル設定(ハンドラに渡すエラーメッセージのレベル)
    logger.setLevel(logging.DEBUG)

    # handlerの生成
    stream_handler = StreamHandler()

    # handlerのログレベル設定(ハンドラが出力するエラーメッセージのレベル)
    stream_handler.setLevel(logging.DEBUG)

    # ログ出力フォーマット設定
    handler_format = Formatter('[%(levelname)s]\t%(asctime)s\tprocess:%(process)d\tthread:%(thread)d\tmodule:%(module)s\t%(pathname)s:%(lineno)d\t%(message)s')
    stream_handler.setFormatter(handler_format)

    # loggerにhandlerをセット
    logger.addHandler(stream_handler)

    return logger
  • 出力結果(ThreadPoolExecutor)
[INFO]  2018-11-12 11:07:23,600 process:17648   thread:14680    module:multi2   multi2.py:50    [main start]
[DEBUG] 2018-11-12 11:07:23,601 process:17648   thread:16028    module:multi2   multi2.py:33    [download start] sleep: 2.0 01PavanePourUneInfanteDfuntePourPianoMr19.mp3
[DEBUG] 2018-11-12 11:07:23,601 process:17648   thread:15308    module:multi2   multi2.py:33    [download start] sleep: 3.5 02JeuxDeauPourPianoMr30.mp3
[INFO]  2018-11-12 11:07:53,104 process:17648   thread:16028    module:multi2   multi2.py:39    [download finished] 01PavanePourUneInfanteDfuntePourPianoMr19.mp3
[DEBUG] 2018-11-12 11:07:53,105 process:17648   thread:16028    module:multi2   multi2.py:33    [download start] sleep: 1.5 03SonatinePourPianoMr40-Modr.mp3
[INFO]  2018-11-12 11:07:54,921 process:17648   thread:15308    module:multi2   multi2.py:39    [download finished] 02JeuxDeauPourPianoMr30.mp3
[DEBUG] 2018-11-12 11:07:54,923 process:17648   thread:15308    module:multi2   multi2.py:33    [download start] sleep: 2.0 04MouvementDeMenuet.mp3
[INFO]  2018-11-12 11:08:05,049 process:17648   thread:16028    module:multi2   multi2.py:39    [download finished] 03SonatinePourPianoMr40-Modr.mp3
[DEBUG] 2018-11-12 11:08:05,050 process:17648   thread:16028    module:multi2   multi2.py:33    [download start] sleep: 2.0 05Anim.mp3
[INFO]  2018-11-12 11:08:13,564 process:17648   thread:15308    module:multi2   multi2.py:39    [download finished] 04MouvementDeMenuet.mp3
[INFO]  2018-11-12 11:08:17,042 process:17648   thread:16028    module:multi2   multi2.py:39    [download finished] 05Anim.mp3
[INFO]  2018-11-12 11:08:17,043 process:17648   thread:14680    module:multi2   multi2.py:61    [main finished]

ログの時刻に注目すると、最初に2つのファイルのダウンロードが開始され、 そのうち1つ終了すると、次のファイルのダウンロードが開始される

  • 出力結果(ProcessPoolExecutor)
[INFO]  2018-11-12 11:09:59,411 process:14408   thread:13500    module:multi2   multi2.py:50    [main start]
[DEBUG] 2018-11-12 11:09:59,553 process:16508   thread:948      module:multi2   C:\Users\121799\PycharmProjects\concurrent\multi2.py:33 [download start] sleep: 3.5 01PavanePourUneInfanteDfuntePourPianoMr19.mp3
[DEBUG] 2018-11-12 11:09:59,553 process:16928   thread:1588     module:multi2   C:\Users\121799\PycharmProjects\concurrent\multi2.py:33 [download start] sleep: 2.5 02JeuxDeauPourPianoMr30.mp3
[INFO]  2018-11-12 11:10:23,491 process:16508   thread:948      module:multi2   C:\Users\121799\PycharmProjects\concurrent\multi2.py:39 [download finished] 01PavanePourUneInfanteDfuntePourPianoMr19.mp3
[DEBUG] 2018-11-12 11:10:23,493 process:16508   thread:948      module:multi2   C:\Users\121799\PycharmProjects\concurrent\multi2.py:33 [download start] sleep: 2.5 03SonatinePourPianoMr40-Modr.mp3
[INFO]  2018-11-12 11:10:34,172 process:16928   thread:1588     module:multi2   C:\Users\121799\PycharmProjects\concurrent\multi2.py:39 [download finished] 02JeuxDeauPourPianoMr30.mp3
[DEBUG] 2018-11-12 11:10:34,173 process:16928   thread:1588     module:multi2   C:\Users\121799\PycharmProjects\concurrent\multi2.py:33 [download start] sleep: 2.0 04MouvementDeMenuet.mp3
[INFO]  2018-11-12 11:10:37,539 process:16508   thread:948      module:multi2   C:\Users\121799\PycharmProjects\concurrent\multi2.py:39 [download finished] 03SonatinePourPianoMr40-Modr.mp3
[DEBUG] 2018-11-12 11:10:37,541 process:16508   thread:948      module:multi2   C:\Users\121799\PycharmProjects\concurrent\multi2.py:33 [download start] sleep: 2.5 05Anim.mp3
[INFO]  2018-11-12 11:10:46,934 process:16508   thread:948      module:multi2   C:\Users\121799\PycharmProjects\concurrent\multi2.py:39 [download finished] 05Anim.mp3
[INFO]  2018-11-12 11:10:47,823 process:16928   thread:1588     module:multi2   C:\Users\121799\PycharmProjects\concurrent\multi2.py:39 [download finished] 04MouvementDeMenuet.mp3
[INFO]  2018-11-12 11:10:47,824 process:14408   thread:13500    module:multi2   multi2.py:61    [main finished]
  • ProcessPoolExecutorはプロセス間によって実現しているため、いつくか制限がある
    • 関数の引数および戻り値は、pickleを使ってシリアライズ可能なオブジェクトでなければいけない
    • 関数自体もプロセス間で渡さなければならない。インスタンスメソッドもNG。ラムダ式はOK
    • 関数の中で副作用としてグローバル変数を書き換えるなどしても、呼び元のプロセスには反映されない
補足
  • pickleモジュールはPythonのオブジェクトを直列化・非直列化するための機能を提供している 直列化(Serialize)というのはプログラミング言語においてオブジェクトをバイト配列などの表現に変換すること
参考URL

VagrantのGuest GuestAdditionsについて

共有フォルダを作成したいときに、 「Guest Additions Version」と「VirtualBox Version」が違うとエラーが発生する

環境

>vagrant plugin install vagrant-vbguest
Installing the 'vagrant-vbguest' plugin. This can take a few minutes...
Installed the plugin 'vagrant-vbguest (0.16.0)'!
  • VagrantFile
#
# Note: set environment vars "HOSTNAME" and "IP", or replace the below
#

Vagrant.configure("2") do |config|
  config.vm.box = "bento/centos-7.3"
  config.vm.hostname = "redash"
  config.ssh.insert_key = false
  config.vm.network "private_network", ip: "192.168.56.203"
  config.vbguest.auto_update = false
  config.vbguest.no_remote = true
  config.vm.provider "virtualbox" do |vb|
    vb.name = config.vm.hostname
    vb.memory = "2048"
    vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
    vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
    vb.customize ["setextradata", :id, "VBoxInternal/Devices/VMMDev/0/Config/GetHostTimeDisabled", 0]
    vb.customize ["modifyvm", :id, "--cableconnected1", "on"]
  end
  config.vm.provision "shell", inline: <<-SHELL
    sudo systemctl restart network.service
    sudo yum -y update
    sudo yum install -y zsh vim tree telnet dstat git tig
    sudo gpasswd -a vagrant vboxsf
  SHELL
end

Guest Additionsのアップデートと再起動

>vagrant vbguest
>vagrant reload
>vagrant vbguest --status
Got different reports about installed GuestAdditions version:
Virtualbox on your host claims:   5.1.26
VBoxService inside the vm claims: 5.2.12
Going on, assuming VBoxService is correct...
[default] GuestAdditions 5.2.12 running --- OK.
>vagrant halt

virtualbox側で、共有フォルダの設定を正しくする(不要かもしれないが...)

  • [設定] -> [共有フォルダ] -> 自動マウントの設定

  • vagrantの起動

>vagrant up

上記で起動しないと、共有フォルダは設定されない

参考URL

https://qiita.com/isaoshimizu/items/e217008b8f6e79eccc85

vagrantのshared folderのmountに失敗してしまった場合

VirtualBoxディレクトリ共有を行うために使っているVirtualboxGuestAdditionというツールのバージョンが, ホストとゲストでずれているとこのような問題がおこるらしい

$ vagrant plugin install vagrant-vbguest
$ vagrant vbguest

https://qiita.com/ak-ymst/items/bdc37aaf53f857d37fcc

vagrant reloadコマンドから起動しないと、 共有フォルダは設定されない

rootかvboxsfグループのユーザーしかアクセスできないため、 既存ユーザーをvboxsfグループに追加しておく。有効にするため一度再起動したら、 共有できるようになっているはず。 単に共有さえできればいいならここまでで設定は終わり。

# gpasswd -a vagrant vboxsf
# reboot

共有フォルダの設定

https://qiita.com/centipede/items/5b3cb4965618993cefec

pythonでS3にgzip形式でPUTする

PythonでS3にgzip形式でPUTする際は以下のようにすればいける。

Python 2.7.5

import boto3
from boto3.session import Session

buff = '111,222,333'

# output csv
session = Session(aws_access_key_id=your_access_key_id,
                    aws_secret_access_key=your_secret_access_key',
                 )

bucket = "your-bucket"
key = "{}.csv.gz".format("yyyy-mm-dd")

io = StringIO()
with GzipFile(fileobj=io, mode='wb') as f:
    f.write(buff)

body = io.getvalue()
s3 = session.resource('s3')
s3.Bucket(bucket).put_object(Key=key, Body=body, ACL='public-read', ContentEncoding='gzip')

Lambdaの呼び出し元について

LambdaFunctionには2つの呼び出し元がある

  1. ストリームベース
  2. ストリームベースではない
1.ストリームベース
2.上記以外はストリームベースではない呼び出し

ストリームベースではないイベントソースからの呼び出しは2種類がある

  • 同期呼び出し
    • AWS CLIや各SDKにてLambda関数をInvokeした場合(デフォルト動作)
    • API Gateway(デフォルト動作)※参考AWS Lambda 関数の API GatewayAPI を作成する
    • Cognito
    • Alexa
    • Lex
  • 非同期呼び出し(非同期のLambdaFunctionでエラーが発生した場合、自動的に間隔をあけて2回再試行される)
    • AWS CLIや各SDKにてInvocationType=EventでInvokeした場合
    • API Gateway(ヘッダでEvent指定時)※参考AWS Lambda 関数の API GatewayAPI を作成する
    • AWS IoT
    • CloudWatch Events(スケージュル含む全てのトリガー)
    • CloudWatch Logs
    • CodeCommit
    • S3
    • SNS
    • SES
    • CloudWawtch Logs
    • KinesisFirehose
    • CloudFormation(Lambdaを利用したカスタムリソース)
    • CodeCommit
    • AWS Config

www.h4a.jp dev.classmethod.jp