Python memcached

Python学習【365日チャレンジ!】145日目のマスターU(@Udemy11)です。

あまりにお腹がすきすぎると意識を失ってしまいそうになるときがあります。

意識を失う前になにか食べるので、実際に意識を失ったことはありませんが、なにかに集中して時間を忘れると気づいたときにはお腹がすきすぎているなんてことは何度がありました。

それくらい集中してPythonを学べばもっと上達は早くなるんだろうなーと思う今日このごろです。

それでは今日もPython学習を始めましょう。

昨日の復習

昨日はDBM(DataBase Management)を学習しました。

非常に簡易なデータベースで、辞書型データを使って利用しましたが、扱えるのは文字列だけで、Integer(整数)などを扱うことはできないので、ほんとに簡単な使い方で活用するとのことでした。

DBMの詳細については、こちらの記事をごらんください。

今日は、memcachedについて学習しましょう!

memcachedとは

memocachedは、高性能な分散メモリキャッシュサーバーですが、よくわからないですよね。

簡単に解説すると、処理を高速化するためのものです。

それでもよくわからないかも。。。

基本、Webアプリケーションなどは、データベースとのやり取りを行うことで要求された処理をしているわけですが、データベースへの問い合わせが混雑すると処理が遅れてしまいます。

処理が遅れないように、メモリにキャッシュしてデータベースへの問い合わせを調整してくれるツールがmemocachedで、いってみればスーパーの駐車場案内係みたいなものですね。

とりあえずいっぱいになったら待たせておいて、空いたら案内するって感じかな。

それではまず、memcachedをインストールしていきましょう。

memcachedのインストール

memcachedのインストールは、brewを使ってインストールします。

brewのインストールについては、こちらの記事をごらんください。

memcachedをインストールするには、ターミナルでbrew install memcachedを実行します。

Python memcached

brewのアップデートがたくさんあったようで、私は結構時間がかかりました。

次に、pipインストールを使って次のコマンドpip install python-memcachedを実行し、python-memcachedをインストールします。

Python memcached

私のPycharmの調子が悪いのか、pipインストールで入れてもPythonファイルでインポートエラーが起こっていたので、Preferencesからインストールしました。

Preferencesからのインストールについては、こちらの記事を参考にしてください。

インストールが完了すれば、実際にコードを書いていきます。

memcachedの使い方

それでは早速memcachedを使っていきますが、最初にターミナルからmemcached -vvを実行します。(終了するときは、control+c

Python memcached

これでPythonからmemcachedを利用することができます。

Pythonファイルに次のコードを書いて実行してみましょう。

import memcache

db = memcache.Client(['127.0.0.1:11211'])

db.set('test_page', 'value1')
print(db.get('test_page'))

ホストが127.0.0.1で、ポートが11211ですが、127.0.0.1localhostにしても大丈夫です。

コンソールへの出力はvalue1ですが、ターミナルを見てみると、どのような処理がされているのかがわかります。

Python memcached

処理としては、ローカルホストにmemcacheを辞書型でセットして、キーがtest_pageのバリューを取り出しています。
最後は、接続を閉じています。

キャッシュの時間をコントロール

memcachedはメモリーにデータをキャッシュしますが、その時間はデフォルトで5分です。

キャッシュの時間を1秒にして、timeモジュールを使って処理を2秒待ってから実行すると、保存したデータは1秒でクリアーされているので、出力はNoneが返されます。

import time

import memcache

db = memcache.Client(['localhost:11211'])

db.set('test_page', 'value1', time=1)
time.sleep(2)
print(db.get('test_page'))

最初に標準モジュールtimeをインポートして、db.setの引数time=1でキャッシュの時間を1秒にしてからtime.sleep(2)で出力を2秒待っています。

データはすでにクリアされているので、コンソールへの出力結果はNoneになります。

SQLiteと組み合わせる

次に、SQLiteと組み合わせてデータベースを扱ってみましょう。

import sqlite3

import memcache

db = memcache.Client(['localhost:11211'])

conn = sqlite3.connect('test_sqlite3.db')
cursor = conn.cursor()
cursor.execute('CREATE TABLE persons(employ_id INTEGER PRIMARY KEY AUTOINCREMENT, name STRING)')
cursor.execute('INSERT INTO persons(name) values("Mark")')
conn.commit()

def get_employ_id(name):
    employ_id = db.get(name)
    if employ_id:
        return employ_id
    cursor.execute('SELECT * FROM persons WHERE name = "{}"'.format(name))
    person = cursor.fetchone()
    if not person:
        return Exception('No employ')
    employ_id, name = person
    db.set(name, employ_id, time=60)
    return employ_id

print(get_employ_id("Mark"))

cursor.close()
conn.close()

流れを見ていきましょう

sqlite3モジュールを追加で読み込んで、7行目から11行目までは、以前学習したSQLiteの扱いと同じです。employ_idをプライマリーキーの整数にして、自動で番号が振られるようにして、名前は、STRINGERで指定したのち、10行目でMarkのレコードを追加しています。

13行目から23行目は関数の定義ですが、まずmemcachedでキャッシュに保存されているnameから引数nameと同じレコードのkeyの値employ_idを取り出し、値が存在すればemploy_idを返します。

それ以外のときは、SQLiteのデータベースから引数nameを取得して、最初のデータをcursor.fetchone()personに代入します。

personに値がない時はエラー(No employ)を返しますが、存在する場合は、personをアンパッキングして、60秒間だけ取り出したnameemploy_idを保有し、employ_idを返します。

最後に25行目で、Markを引数にして関数get_employ_idを実行して出力しているので、出力結果は自動的に入力された1になります。

キャッシュから読み込む

例えばブラウザーでページを更新しても古いページが表示されることがあります。

これは、memkcachedの仕業だったのかしれません

要するに、いちいちデータベースに問い合わせることなく残されたキャッシュを表示するのため、高速にページを表できるのと同じような役割を持っています。

リクエストを送って返ってくるのをまつより、自分のMacの中に保存されていれば、より高速にデータを表示できるというわけです。

要するにキャッシュ化から読み込むことで、スピードアップを図ることができるということです。

いろいろと勉強すればするほど、もっと勉強しないといけないことに気付いてしまうので、ほんと悩ましい限りです。

今日は、このくらいにして明日もしっかり学習したいと思います。

それでは、明日もGoodbye