このBlogは移転しました。今後は aish.dev を御覧ください。

Python.jp Discordサーバ雑感

Python.jp Discordサーバ の運用を本格的に開始してから半年以上経ったので、感想など。

ユーザ層

Pythonのユーザ層いうとビジネス層というか、おっちゃんが多いイメージがあるのだか、Discordというゲームで広く使われているシステムなためか、アクティブな参加者は若年層・学生が多いようだ。Discordの利用規約で禁止されている小学生の存在が発覚して、ご退去いただいたこともある。

Discord bot

また、プログラマプログラマ希望者だけではなく、単にDiscordをチャットとして利用している人たちも多い。こういう人たちはプログラミングの知識はあまりないが、ゲームを楽しく遊ぶためのツールとして、Discordにいろんなbotを入れて活用している。そのうち、出来合いのbotでは満足できなくなって、自分なりのbotを作りたくなってきた人たちだ。

私は、この「Discord botを作りたい素人」みたいなのが大好きだ。自分の子供のころを思い出す。プログラミングを仕事や就職の道具や教養として身に着けようというのではなく、なにか楽しみがあって、その楽しみをより満喫するするためにコンピュータやインターネットを活用したい。こういうのがHackというもので、一番楽しいプログラミングだと思う。

質問と回答

現在、Python.jpサーバでは、こういう人たちからのDiscord botに関する質問が多い。プログラミング未経験者がほとんどで、質問も的を得ていない。「この質問、往年のJavaHouseだったらどんだけ炎上するだろ」と怖くなるレベルの質問もあるが、今のところは常連のDiscord.py勢が丁寧に回答してくれていて、感謝に堪えない。

こういった初心者の質問への回答は、回答者の意欲と善意に依存しているのでいつまで続くかはわからない。しかし、現在のところ、とても円滑かつ円満にQ/Aが進行している。これは、

  • かんたんなDiscord botはコード量が比較的少なく、初心者でも取り組みやすい
  • プログラミング未経験者が多く、経験者にはできないような質問を躊躇なくしてくる
  • そういった質問でも回答がつくため、他の初心者もまた質問してくる
  • Discord bot経験者が多く、同じような問題を解決したことがあることが多い
  • まだそれほど経験が深くない参加者も多く、初心者に同情的である
  • 初心者が最初にPython.jpサーバでいろいろ教わったため、成長して自然と回答者になってしまった

あたりが要因なのではないかと思ってる。現在のところ、質問者と回答者の数とレベルが、ちょうどいい感じでバランスが取れているのだろう。

また、質問者がプログラミングの初心者であっても、「Discordでこういうことをしたい」という要望そのものは決して低レベルなものだけでなく、有識者の好奇心を刺激して「こうすればできるんじゃない?」という反応を引き出しやすいように思う。

Q/Aの余禄

こういった感じでDiscord関連でにぎわうようになってから半年以上たつが、あまり口出しせずに見ていると、かなりの速度で初心者を脱しつつある若者が目に付く。

よく言われるように、物事は教わるよりも教えるほうが身につくものだ。いろいろな質問の答えを考えるだけでも役に立つ。

また、アマチュアプログラマは、プログラミング言語やOSなどについてある程度覚えてしまうと、次に何をやったらいいのかわからなくなってしまうことが多い。特に、プログラミング適性の高い人はあっという間に基礎を覚えてしまうため、すぐに行き先を見失ってしまう。

Discord botは比較的シンプルで、実行環境を作って実験しやすいテーマだ。こういったテーマで、いろいろな質問が流れてくる、というのは、初心者が経験を積むには好都合だったのだと思う。いろんな経験を積めたのではないだろうか。

プログラミングという技術でも、経験というのが結構大事だ。一度やったことを、一回で覚えられる人は少ない。何度か繰り返して考え、調べ、実際に書いていると、体にパターンとしてしみこんでくる。実戦経験が重要なのだ。いろいろ能書きを垂れる前に、とりあえずプログラム100本ぐらいは書いてほしいものである。

f:id:atsuoishimoto:20190306014924j:plain:w400

こう考えると、未経験者や初心者が質問しやすい環境を整えるというのは、単に初心者をサポートするだけではない。経験を積んだ中堅を育成するために必要なのだと思う。初心者をサポートするために質問しやすい環境を作るのではなく、むしろ中堅予備軍が経験を積みやすいように初心者の質問が集まる場を作る、というのが重要なのかもしれない。

また、こういった場では、「答えを教えちゃうよりも自分で考えるようにしたほうが良いのでは?」とか余計なことを考えず、正解なり完成したコードなりをすんなり示してもらったほうが、良い結果につながると思う。我々は教育に関しては素人なのだから適切な問題設定などできないし、質問者が回答にたどりつけなかった時のフォローも難しい。なにより回答陣どうしでその回答について語り合うことができなくなってしまうので、問題の深掘りにつながらなくなってしまうのがもったいないと感じる。

これから

今のところうまく機能しているような気がしてるので、特にいじる予定はない。ただ、Discordの話題ばっかりというのも寂しいので、Webプログラミング勢や機械学習勢などの若者も、ぜひともご来駕賜りたいと思う次第である。

docs.python.jpでのドキュメント公開終了

これまで、python.jpではPythonの日本語ドキュメントを公開してきたが、この度、ドキュメントのホスティングを終了し、docs.python.org へのリダイレクトのみをおこなうようになった。

www.python.jp

実に喜ばしいことである。これまで、日本語ドキュメントは python.jp においてある私家版でしかなかったが、python.orgで公開されることで、一定の公式っぽさを得ることができる。

また、python.jpは私が一人でほそぼそと、さくらインターネットの一番安いVPSで管理運用してきた。しかし、これからはPython本家の運用チームできっちり運用していただけるのである。

別に難しいことをしていたわけではないが、python.jp運営のプレッシャーはちょっとしたものだった。ここ近年のPythonブームも、私がちょっとしくじってドキュメントを参照できなくなる、なんてことになると、多少なりともケチがつきかねない。Python.jpにはもうドキュメントもメーリングリストも存在しない。安心して安サーバを利用できるというものだ。

Python.jpのこれから

Pythonドキュメント日本語訳がpython.jpから離れる、ということは、私個人にとっては非常に感慨深い。

もともと、python.jpドメインは、翻訳したPythonドキュメントを公開するために取得したものだ。取得したのは2001年のことで、この頃はまだGithubは存在せず、SourceForgeがようやく使われだした頃だ。無料でドメインホスティングしてくれるサービスはなかったため、一般企業にサーバを貸していただいて運用していた。VPSではなく、物理的なハードウェアを一台丸々である。まだVPSも一般的ではない時代だったのだ。

で、今回、Pythonドキュメント翻訳プロジェクトがPython.jpから完全に分離するということは、Python.jpは一定の役割を終えた、ということになるのだろう。18年間、お疲れ様でした。

とはいえ、せっかく Python.jp というかっこいいドメインが手元にあるのだから、なにか有効活用したい。現在、Python関連のニュースや企業からの求人などを無償で公開したり、Pythonの環境構築ガイドを公開したりしているが、もうちょっと良い使いみちがないものかと思っている。なにか良い案があれば、Python.jp Discordサーバ などでご提案いただければ幸いである。

Pythonの高速化?

たまに、「Pythonの高速化」なんてブログを見かけることがある。書いてあるのは、たいてい

s = 0
for i in list_of_ints:
   s += i

と書くより、

s = sum(list_of_ints)

のほうが速い!なので sum() 使おう!とかだ。

たしかに、sum() は速い。Pythonインタープリタによるループの繰り返しを行わず、高速なC言語による処理が行われるためだ。特に、リストやタプルが引数に指定されている場合、さらに高速に実行できるように特別扱いされている。

100,000,000個の整数のリストで処理時間を計測してみると、for ループ版では 3.5秒、sum() 版では 2.2秒となった。すごい、2/3になった!forループ糞だな!

…どうだろう…

まず、こういったサンプルプログラムは、極端に単純化されている。私はもう数十年に渡ってさまざまなプログラムを書き続けて来たが、「一億件の整数を加算する」だけのプログラム、というのにお目にかかったことがない。

ふつうは、まず一億件のデータはかならずどっかから取得しなければならない。通常はデータベースやテキストファイルなどにアクセスし、読み込む必要がある。

整数データとはいえ、一億件を普通に読み込めばざっと10秒ぐらいはかかるだろう。ということは、加算の処理で1.3秒節約すると、13.5秒が12.2秒になってそれはそれで意味のある最適化ではあるが、全体としてみればそれほど目覚ましい成果ではない。

こういったケースでは、例えば入力データがテキストデータなら、事前に入力ファイルを分割しておいてデータの読み込みと計算を多重化する、などの手段が有効で、もっと大きな成果を期待できる。

RDBからの読み込みであれば SELECT sum(xx) FROM ... のようにRDBの集計機能を利用すれば、一秒以下で計算できるだろう。

Pythonの書き方を工夫するしてパフォーマンスを改善する、というのは、結局は同じアルゴリズムを、ちょっと無駄の少ない手順でやる、ということに過ぎない。当然、処理時間に多少の差が出ることはあっても、それほど大きな差にはならない。

sum() を使った加算が手作りのループより約3割速くなる、というのが、よく使われる最適化では最も効果の大きい例だが、これもせいぜい数%程度の差しか生じないだろう。

昔は、文字列の結合は

s = ''
for c in words:
    s = s + c

と書くと O(N**2) の時間が必要だが、

s = ''.join(words)

なら激速い、なんてのもあった。しかし、これはかなり昔、ほぼ同等な処理時間となるように最適化されてしまった。

ということで、Pythonでプログラムを書く時には、「パフォーマンスが出る書き方」ではなく、「読みやすい書き方」を心がけよう。

パフォーマンス重視で書いても、そんなには速くはならない。

for 文を使ったほうが読みやすい、と思ったら、迷わずに for 文を使えばよい。

単純なケースなら、sum() のほうが読みやすいだろう。そういった場合は容赦なく sum() を使おう。

読みやすく書いて、全体のアルゴリズムを改善しやすくすること心がけよう。

時間は、ボトルネックの抽出とその解消に使おう。

こまごまとしたチューニングに時間と体力を消費しないようにしよう。

ボトルネックのチューニングを実施した後、最後のダメ押しで for 文の除去などのチューニングを加えるのはもちろん問題ないが、それは一番最後に行うことで、最初から考えるようなことではないのである。

Python.jp SlackからDiscordへ

これまで、python.jp ではSlackチームを用意していたが、こちらの利用は取り止めて、Discord に移行することにした。

書き込みはそれほどなかったものの、Python.jpチームには、約1000アカウントが登録されていた。そこそこな規模だろう。Slack->Discordへの大規模な移行としては Reactチーム の例があるが、こちらは別に Slack からなにかの制限を受けたというわけではない。

では、なぜDiscordに移行するかといえば、Slackというのはやはりオープンなコミュニティのチャットツールとしてはイマイチだと思うからだ。ReactさんのBlog にあるように、Slackのユーザ登録は面倒だし、複数のチームに所属する場合はそれぞれのチームでいちいちログインしなければならない。コミュニティ用のツールではないので特定ユーザのミュートやBanなどの機能もない。

また、Slackで一番問題だと思うのは、無料のフリープランでは過去の書き込みを最大10000件までしか参照できない点だ。もちろん、払うものを払えばいいのだが、1000ユーザだと月85万円になる。道楽で払う額ではない。

この点、Discordの場合はログの保持件数に制限がない。無料で使うのは気が引ける、という人は、個別に 月額$4.99 でDiscordをサポートできる。チームごとに運営者がまとめて支払う必要はない。

気になる点

機能的にSlackではできてもDiscordではできなくなる点がいくつかあるが、多少の機能不足はあっても、ログ保持件数の制限がないというメリットのほうが重要だと思う。でも、Discordさんなんとか対応してくれないかなと願う次第だ。

個別の書き込みにURLが割り当てられていない

Slack では、それぞれの書き込みへのリンクを取得してあとから参照できるが、Discord にはこの機能がない。ちょっと離れた書き込みへのリプライなどは書きにくそうだ。

組み込みのBot機能が弱い

Discord には、SlackBot に相当する簡易Bot機能がない。また、GoogleTwitterなどと連携するbotもデフォルトでは用意されていないので、各サーバが自前で構築する必要がある。

絵文字の登録数に制限がある

Discord では最大50件しか登録できない。これだと、全ユーザに権限を開放して自由に登録できるようにするのは、ちょっと躊躇してしまう。

Reply機能がない

SlackのReply見にくくてきらいだから別にいい

今後について

Python.jp Slackチームは、2016年12月30日 に公開された。それから約1年半、とくに宣伝はしなかったが、コンスタンスに利用者が増え続け、いつの間にか1000名を超える大所帯となっていた。

もともと何らかのプランがあって作成したわけではなく、とりあえず建ててみるかー程度のノリだった。特に目的や利用方法を決めていたわけではないが、これだけの人々が登録しに来るというのは、やはりそれなりのニーズがあるのだろう。

しかし、Python.jp Slackチーム、登録者数は多くても、たまに初心者の質問があったりする程度で、書き込みはほとんどなかった。どんなコミュニティでもROMが主流なのは同じだろうが、さすがに書き込みがなさすぎる。1000名のPythonistaが息をひそめてSlackを見つめているかと思うと、なんだかこっちまで息が詰まる。

というわけで、なにかPythonに関することで、ちょっと話したいことや、人に尋ねたいことがあったら、気軽に python.jp Discordサーバ に書き込んでいただきたい。

Chatというのはあまり細かいことを気にせずに書き込める、というのが身上だと思う。気軽に雑談するつもりで利用していただけるようなサーバとして運営したいと思っているので、ご協力いただければ幸甚だ。

Dell XPS 13 (9370) に Ubuntu 16.04 をインストールした

Dell XPS 13 (9370) の全部入り( i7-8550U・4Kタッチパネル・1TB SSD ・16 GBメモリ) を購入した。

これまでのところ、思ったより使い勝手がよい。キーボードはいい感じだし、パームレストのカーボンファイバも触り心地が良い。

液晶は非光沢がなくて光沢のみということでターミナルの背景におじさんが出現する不具合が怖かったが、あまり気にならない。手元のMacBook Airと比べても遜色ない気がする。

Linux環境でのタッチパッドも、設定でかなりまともに使えるようになった。 ← 後述のとおり、16.04ではダメだったので17.10に切り替えた

以下作業メモ

事前準備

  • どっちにしろWindows 10 Proをインストールするので、プリインストールのWindows 10 Homeは潔くパーティションごと削除。

  • UbuntuWindowsのインストール用USBを作成する。 XPS 13 (9370) では、Type-AのUSBメモリがいくつあっても無意味。Type-C - Type-A の変換アダプタを用意する。

  • Ubuntu 16.04もWindows 10も、インストールメディアで立ち上げた状態ではWiFiBluetoothが使えないので、USB Type-C で使えるテザリングかLanアダプタを用意する。

Ubuntuのインストール

XPS 13を再起動し、Dellのロゴが表示される前にF2キーを連打し、BIOS設定画面を表示する。

BIOS画面で、

  1. SATA-controllerをRaid -> AHCI とする。
  2. SecureBoot をオフにする

UbuntuUSBメモリを挿し、再起動する。Dellのロゴが表示される前にF12キーを押し、ブートデバイスにUSBを選択する。

Ubuntu 16.04インストールメディアに含まれているドライバでは、XPS 13のBluethoothやWiFi、画面のスケール設定などが動作しない。

とりあえず 16.04 をインストールし、LanアダプタやスマホのUSBテザリングなどを使って sudo apt update; sudo apt upgrade して再起動すれば正常に動作する。

libinput

[追記] 以下の手順で16.04にlibinputをインストールすると、ログインーログアウトを繰り返すとハングする模様。。。

デフォルトの状態ではタッチパッドpalm detectionまじ使えないので、次のページを参考に libinput をインストールする。

askubuntu.com

$ sudo apt install xserver-xorg-input-libinput

/usr/share/X11/xorg.conf.d/40-libinput.conf

# Match on all types of devices but tablet devices and joysticks
Section "InputClass"
    Identifier "libinput pointer catchall"
    MatchIsPointer "on"
    MatchDevicePath "/dev/input/event*"
    Driver "libinput"
EndSection


Section "InputClass"
    Identifier "libinput keyboard catchall"
    MatchIsKeyboard "on"
    MatchDevicePath "/dev/input/event*"
    Driver "libinput"
EndSection

Section "InputClass"
    Identifier "libinput touchpad catchall"
    MatchIsTouchpad "on"
    MatchDevicePath "/dev/input/event*"
    Driver "libinput"
    Option "Tapping" "True"
    Option "NaturalScrolling" "True"
EndSection

Section "InputClass"
    Identifier "libinput touchscreen catchall"
    MatchIsTouchscreen "on"
    MatchDevicePath "/dev/input/event*"
    Driver "libinput"
EndSection

Section "InputClass"
    Identifier "libinput tablet catchall"
    MatchIsTablet "on"
    MatchDevicePath "/dev/input/event*"
    Driver "libinput"
EndSection

この状態だとタッチパッドの設定をGUIで行えないので、次のページを参考に設定を行う。

github.com

.profile

touchpad_id=$(xinput --list | grep -i "Synaptics Touchpad" | xargs -n 1 | grep "id=" | sed 's/id=//g')

# touchpad_id='13'

natural_scrolling_code=$(xinput --list-props "$touchpad_id" | grep "Natural Scrolling" | awk '{print $5}' |  grep -o '[0-9]\+')
xinput --set-prop "$touchpad_id" "$natural_scrolling_code" 0

tap_to_click_code=$(xinput --list-props "$touchpad_id" | awk '/Tapping Enabled \(/ {print $4}' | grep -o '[0-9]\+')
xinput --set-prop "$touchpad_id" "$tap_to_click_code" 1

accel_speed_code=$(xinput --list-props "$touchpad_id" | awk '/Accel Speed \(/ {print $4}' | grep -o '[0-9]\+')
xinput --set-prop "$touchpad_id" "$accel_speed_code" "1.0"   # -1.0 ~ 1.0

disable_while_typing_code=$(xinput --list-props "$touchpad_id" | grep "Disable While Typing Enabled (" | awk '{print $6}' |  grep -o '[0-9]\+')
xinput --set-prop "$touchpad_id" "$disable_while_typing_code" 1

Windowsのインストール

Windows 10 Fall Creators Updateのインストールメディアでは、WiFi/Bluetooth が認識できない。

http://www.dell.com/support/home/jp/ja/jpbsd1/products/laptop/xps_laptop?app=drivers を参照し、Dell Mobile Connect Driver をインストールするとWifiに接続できる。

リブートすると、デフォルトでWindowsがブートしてしまうので、Ubuntugrubでブートする場合は、UbuntuBoot-repair をインストールして設定を変更する。

https://askubuntu.com/questions/666631/how-can-i-dual-boot-windows-10-and-ubuntu-on-a-uefi-hp-notebook

hashlibのハッシュアルゴリズム、計算速度ってどのぐらい差があるの選手権

雑に図ってみた (Python 3.6.4)

対象ファイル: 画像ファイル約20000件(2GB弱)

アルゴリズム 処理時間(秒) ファイル読み込み時間は含まず
md5 2.536
sha1 1.798
sha256 3.873
sha384 2.591
sha512 2.626

まとめ

sha1はええ。md5そんな速くねえ。sha512とそんな変わんねえ。

コード

import hashlib, sys, pathlib, time

sizes = []
times = []

HASH = gatattr(hashlib, sys.argv[1])

def h(b):
    f = time.time()
    h = HASH(b).digest()
    times.append(time.time()-f)
    sizes.append(len(b))

imgs = pathlib.Path(sys.argv[2]).glob("*.jpg")
for i in imgs:
    h(i.read_bytes())

print(len(sizes), sum(sizes), sum(times), sum(times)/len(times))