<commit_before>---
layout: post
title: "Simplest Python RPC"
date: 2020-02-06
excerpt: ""
tags: [python, rpc]
comments: false
---

# Simplest Python RPC

## 目次
 - 今のPythonのRPCは種類が多すぎる
 - 標準ライブラリで実行できる価値
 - コードの説明
 - 実際に動かしてみて


## 今のPythonのRPCは種類が多すぎる
 2020年現在、数多くのRPCがOSSとして公開されていますが、種類が多すぎる点と、それに伴う選択コストの増加と、評価コストの増加、学習コストの増加が個人的な課題であると感じています。  

 社会人をやっているととにかく時間が貴重なので、次々現れるライブラリを検討していたり、使い方を学んだりしているのは、PoCを素早く行う場合やAPIなど閉じた小さいプロダクトを作る際には適切ではありません。  

 Pythonでは `multiprocessing` の中に `manager` クラスが存在して、multiprocessing時のプロセス間通信をネットワーク越しに動作させることで、高性能なRemote Procudure Callを実装することができます。  

 Remote Procudure Call(以下, RPC)とは、ネットワーク上の別のコンピュータで、何らかの処理を呼び出したり、処理させたりすることで、大規模な分散処理を行う際に便利です。 

## 標準ライブラリで実行できる価値
 数多くのライブラリを使ってきたのですが、そのライブラリのメンテナがいなくなったりpull requestを受け入れられる体制を持っていなかったり、時間がなかったりなどで多くの、"良さそう"と思われるライブラリが過去の時代に取り残されていきました。  

 できれば、ライブラリ依存せず、かつ簡単に実装できれば、それはPythonが存在する限り(もしくはPythonの中でdeprecatedにならない限り)使用できることになります。  

## コードの説明
 `server` と `client` に分けて考えることができる要素で、`server` は命令を待ち受け、 `client` は命令を発行します。  

**server**  

```python
from multiprocessing.managers import BaseManager as Manager
import os

# インメモリのKVSを想定
obj = {}
def get(k):
    print('get', k)
    return obj.get(k)

def put(k, v):
    obj[k] = v
    print('put', k,v)

# serverのunameを取得(LinuxとかMacOSとかわかる関数)
def get_uname():
    print('get_uname')
    return str(os.uname())

if __name__ == "__main__":
    port_num = 4343
    Manager.register("get", get) # 待受に使う関数を登録
    Manager.register("put", put)
    Manager.register("get_uname", get_uname)
    manager = Manager(("", port_num), authkey=b"password") # ホスト名を空白にすることで任意の箇所から命令を受け入れられる。パスワードが設定できる
    manager.start()
    input("Press any key to kill server".center(50, "-")) # なにか入力したら終了
    manager.shutdown()
```

***client** 

```python
from multiprocessing.managers import BaseManager as Manager
Manager.register("get") # 関数を登録
Manager.register("put")<commit_msg>fix typos<commit_after>---
layout: post
title: "Simplest Python RPC"
date: 2020-02-06
excerpt: ""
tags: [python, rpc]
comments: false
---

# Simplest Python RPC

## 目次
 - 今のPythonのRPCは種類が多すぎる
 - 標準ライブラリで実行できる価値
 - コードの説明
 - 実際に動かしてみて


## 今のPythonのRPCは種類が多すぎる
 2020年現在、数多くのRPCがOSSとして公開されていますが、種類が多すぎる点と、それに伴う選択コストの増加と、評価コストの増加、学習コストの増加が個人的な課題であると感じています。  

 社会人をやっているととにかく時間が貴重なので、次々現れるライブラリを検討していたり、使い方を学んだりしているのは、PoCを素早く行う場合やAPIなど閉じた小さいプロダクトを作る際には適切ではありません。  

 Pythonでは `multiprocessing` の中に `manager` クラスが存在して、multiprocessing時のプロセス間通信をネットワーク越しに動作させることで、高性能なRemote Procudure Callを実装することができます。  

 Remote Procudure Call(以下, RPC)とは、ネットワーク上の別のコンピュータで、何らかの処理を呼び出したり、処理させたりすることで、大規模な分散処理を行う際に便利です。 

## 標準ライブラリで実行できる価値
 数多くのライブラリを使ってきたのですが、そのライブラリのメンテナがいなくなったりpull requestを受け入れられる体制を持っていなかったり、時間がなかったりなどで多くの、"良さそう"と思われるライブラリが過去の時代に取り残されていきました。  

 できれば、ライブラリ依存せず、かつ簡単に実装できれば、それはPythonが存在する限り(もしくはPythonの中でdeprecatedにならない限り)使用できることになります。  

## コードの説明
 `server` と `client` に分けて考えることができる要素で、`server` は命令を待ち受け、 `client` は命令を発行します。  

**server**  

```python
from multiprocessing.managers import BaseManager as Manager
import os

# インメモリのKVSを想定
obj = {}
def get(k):
    print('get', k)
    return obj.get(k)

def put(k, v):
    obj[k] = v
    print('put', k,v)

# serverのunameを取得(LinuxとかMacOSとかわかる関数)
def get_uname():
    print('get_uname')
    return str(os.uname())

if __name__ == "__main__":
    port_num = 4343
    Manager.register("get", get) # 待受に使う関数を登録
    Manager.register("put", put)
    Manager.register("get_uname", get_uname)
    manager = Manager(("", port_num), authkey=b"password") # ホスト名を空白にすることで任意の箇所から命令を受け入れられる。パスワードが設定できる
    manager.start()
    input("Press any key to kill server".center(50, "-")) # なにか入力したら終了
    manager.shutdown()
```

**client** 

```python
from multiprocessing.managers import BaseManager as Manager
Manager.register("get") # 関数を登録
Manager.register("put")
{'fraction_non_alphanumeric': 0.11363037173741102, 'fraction_numerical': 0.009491167940943844, 'mean_word_length': 6.0783582089552235, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3305058', 'n_tokens_mistral': 2403, 'n_tokens_neox': 2250, 'n_words': 234}