2017年06月29日

最近のPython-dev(2017-06)

はてなブックマークに登録

バックナンバー:

PEP 546 -- Backport ssl.MemoryBIO and ssl.SSLObject to Python 2.7

2014年に Python 2.7 をセキュアな状態に保つため、過去に PEP 466 でセキュリティ関連の Python 3.4 の機能が Python 2.7 にバックポートされました。これには ssl モジュールも含まれており、 Python 2.7.9 からは TLS のホストを自動で検証するようになったりシステムの証明書ストアを利用できるようになりました。

今回の PEP 546 は、さらに Python 3.5 で追加された ssl.MemoryBIO と ssl.SSLObject も Python 2.7 にバックポートするものです。これらの API を利用すると、 socket をラップするのではなく、メモリ上のデータに対して TLS の処理ができるようになります。 Windows で winsock2 ではなく IOCP を使ったり、その他非同期IOフレームワークを使うときに socket と TLS を分離できることは重要です。

Python 2.7 自体のメンテは 2020 年に終了しますが、 pip が Python 2.7 のサポートを終了する時期は未定です。実際に今までも、pip はユーザーがほとんどゼロになるまでかなり長い間古い Python をサポートしてきました。

一方で pip が http クライアントとして使っている requests は、将来内部で非同期IOベースにしていくことを検討しています。そして Python 2.7 のためだけに複数の実装をメンテナンスすることには否定的です。

PEP 546 により、 pip と requests が Python 2.7 のサポートを完全に切る前でも、(今年後半にリリースされる) 2.7.14 以降のみのサポートに限定するという形で requests の内部に非同期IO化を実現する余地ができます。

実際にこのシナリオ通りに進まない可能性もあったので、本当に必要なのかどうか議論が白熱しましたが、バックポートが提案されているコードのサイズはCとPythonを足してほんの数百行でしかありません。

最終的に Python 2.7 のリリースマネージャーの Benjamin Peterson さんが、 PEP 466 のときにこのAPIがあったら一緒にバックポートされてたんだし、反対する強い理由は無いよね、といって Accept しました。

PEP 538 warning at startup: please remove it

先月僕が Accept した PEP 538 (C locale のとき LC_COLLATE を C.UTF-8 などに上書きする) が実装され取り込まれました。

さて、この新機能は、 locale の変更に成功したときにはユーザーに最初からUTF-8のロケールを設定するよう促すための warning を、失敗したときは C locale を使ってるから非ASCII文字で問題が出るよという warning を表示していました。

しかし、この warning が単純に鬱陶しいのと、子プロセスを起動して標準入出力を見るようなテストが幾つかのマイナーなプラットフォームで壊れてしまってメンテが面倒になってきました。

ということで、どちらの warning もデフォルトで無効になりました。環境変数に PYTHONCOERCECLOCALE=warn と設定したら有効になるのですが、まぁ誰も使わないでしょうね。

LC_COLLATE を変更して UTF-8 を使えるようにしても問題になることはめったに無いですし、 C locale で非ASCII文字の扱いに制限があるのは Python 3.6 と同じで何かが悪くなったわけは無いので、 warning が無くなることで困るユーザーはほとんど居ないと踏んでいます。

PEP 544 -- Protocols: Structural subtyping (static duck typing)

Python の typing モジュールに structural subtyping のサポートが追加されました。

簡単に説明すると、 typing.Protocol クラスを継承したクラスを定義すると、それがプロトコルになります。プロトコルクラスのメソッドと同じシグネチャのメソッドを持つクラスは、そのプロトコルクラスを継承していなくても、静的チェッカはサブクラスと判断するようになります。

PEP から分かりやすい例を引用します。次の例は、ユーザー定義型 BucketSizedIterable だと型チェッカに教えるために継承を使っています。

from typing import Sized, Iterable, Iterator

class Bucket(Sized, Iterable[int]):
    ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[int]: ...

PEP 544 が承認されると、 Sized や Iterable が Protocol になるので、この Bucket は継承を外しても SizedIterable[int] の部分型だと型チェッカが判断するようになります。

個人的には、 ABC を継承すると起動が遅くなる(クラスの生成が遅くなる)ので継承しなくても良くなるのは嬉しい一方、最初から typing が ABC を使わないでいてくれたらもっと軽量化できたのになーという気持ちもあります。

typing のオーバーヘッドについては先月の Language Summit でも話題になったらしく、MLなどでも議論されているので、これから最適化オプションで削るなどの改善が提案されるかもしれません。

起動高速化

3月号で紹介したのですが、Pythonの起動を高速化するためのプルリクエストを2件出していて、片方 は3月中にマージされ、もう片方 を一昨日マージしました。特に後者は macOS 上での性能向上が顕著で、クリーンインストールされた Python で起動時間が30msくらいだったのが20msくらいに減ります。

site という、 (Python の -S オプションを使わなかったときに) 自動で読み込まれるモジュールがあり、これが sys.path というライブラリを import するときに探す場所などを準備しています。 pip とか apt-get とかでインストールしたモジュールがすぐに使えるようになるのはこの site のおかげです。

この site が、いくつかのディレクトリの場所を決定するために sysconfig という Python の環境情報を集めたライブラリを読み込んでいるのですが、それがそこそこ重いです。そしてさらに macOS の場合、 Framework 内のディレクトリ名 ("Python" だったり "Python3.7" だったり) を調べるために sysconfig から _sysconfigdata という、 Makefilepyconfig.h から大量の変数をかき集めた dict を持つモジュールを利用していました。

Framework 名を sys._framework に入れて _sysconfigdata の必要性をなくし、さらに sysconfig から必要なごく一部分だけを site 内にコピーすることで、起動時間の短縮だけでなく、 mac の場合は多分起動直後のメモリ使用量も1MB程度減っています。

また、 site からのモジュールの import を減らすことによる最適化は、そのモジュールが functools みたいによく使われるものであれば結局アプリケーションの起動時間には寄与しない事も多いのですが、 sysconfig を使うのは site 以外には pipdistutils などのパッケージング関連のツールやライブラリだけなので、今回の最適化は多くのアプリケーションの起動時間・メモリ使用量にもそのまま寄与するはずです。

songofacandy at 22:29│Comments(0)TrackBack(0)Python 

トラックバックURL

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 
Blog内検索
Archives
このブログについて
DSASとは、KLab が構築し運用しているコンテンツサービス用のLinuxベースのインフラです。現在5ヶ所のデータセンタにて構築し、運用していますが、我々はDSASをより使いやすく、より安全に、そしてより省力で運用できることを目指して、日々改良に勤しんでいます。
このブログでは、そんな DSAS で使っている技術の紹介や、実験してみた結果の報告、トラブルに巻き込まれた時の経験談など、広く深く、色々な話題を織りまぜて紹介していきたいと思います。
最新コメント