2015/03/20


Google Code が終了する様です。
Google Open Source Blog: Bidding farewell to Google Code
http://google-opensource.blogspot.com/2015/03/farewell-to-google-code.html

GitHub が無かった頃、私はコード置き場として Google Code を使っていました。とても安定していたし落ちるのを見た事がありませんでした。

残念ながらその Google Code がサービスを終えようとしています。

しかし我々 Gopher のコードには、この Google Code にホスティングされている golang のパッケージが幾らかあります。

Google Code が終了するまでに、私達は移行を完了させなければなりません。

mattn/check-code-google-com - GitHub
https://github.com/mattn/check-code-google-com

パッケージが code.google.com のパッケージに依存しているかどうかを調べてくれます。

例えば mahonia に依存している jvgrep であれば

この様に表示され、code.google.com に依存していない twty であれば

この様に表示されます。中には依存しているパッケージのその依存しているパッケージが code.google.com に依存している事がありますが、それも検索します。-v オプションを付ける事で、どのパッケージが code.google.com に依存しているのかが分かる様になっています。

よろしければどうぞ。

Posted at by



2015/03/10


Vim には netrw というファイラが付属しています。引数にディレクトリを渡すとディレクトリブラウザが開き、HTML のある URL を指定するとダウンロードされた HTML が開き、scp:// の様なプロトコルを指定するとそれにあったファイルの開き方をしてくれます。

最近のモダンな Vim 使いの多くは、NERDTreevimfiler を使っているのですが、正直僕は vim からファイルを操作はしない。思考停止せずに目的のファイルを見つけ出したいし、ファイル操作はファイル操作としてシェルからやりたい。なので深い階層のファイルを見つける為の目的として CtrlP を使ってるし、カレントディレクトリのファイル一覧を出すのに NERDTree を使っていた。

でも NERDTree 遅いなー。ツライなー。そんな風に思っていた時にこれを見つけた。

justinmk/vim-dirvish - GitHub

dired on a diet

https://github.com/justinmk/vim-dirvish

filebeagle をベースとしてとことん小さくしたプラグイン。README には「Note: there are still some bugs. This plugin isn't ready to use yet.」と書かれているけど僕は乗り換えてしまった。

僕は手癖で

$ vim .

とする癖があるのだけど、その時に出るファイル一覧が netrw も NERDTree もとにかく遅い。思考が停止しそうでイラッとする。でも dirvish だと一瞬で開く。本当にファイル操作したいなら :sh で shell やコマンドプロンプトに戻ればいいだけなので僕にはこれが目的にあったプラグインなのです。こういうminimumでenoughなのが僕は好きです。

Posted at by



2015/03/04


先日、Google が開発しているリモートプロシージャコール、gRPC を golang から使うチュートリアルを書きましたが

Big Sky :: Protocol Buffers を利用した RPC、gRPC を golang から試してみた。
http://mattn.kaoriya.net/software/lang/go/20150227144125.htm

今日は ruby と C++ から触ってみたいと思います。はじめに ruby の方ですが、Ruby 2.2.0 でビルドする事が出来ません。どうしても Ruby 2.2.0 から試したい人は、以下の PR にあるパッチを適用して下さい。

Support ruby 2.2.0 by mattn · Pull Request #894 - grpc/grpc - GitHub
https://github.com/grpc/grpc/pull/894

今回の検証は ruby 2.1.0 で行いました。まず proto ファイルから ruby のスタブを吐くには以下の様に実行します。

$ protoc --ruby_out=. --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_ROOT)/bins/opt/grpc_ruby_plugin customer_service.proto

GRPC_ROOT は grpc を checkout したディレクトリですが、システムにインストールした人は適便書き換えて下さい。golang の時の様にスタブが吐かれるのでサーバであれば

#!/usr/bin/env ruby

require 'grpc'
require 'customer_service_services'

class MyServer < Proto::CustomerService::Service
  def initialize()
    @customers = []
  end
  def add_person(arg, call)
    @customers << arg
    Proto::ResponseType.new
  end
  def list_person(args, call)
    @customers
  end
end

def main
  customers = []
  server = GRPC::RpcServer.new
  server.add_http2_port('0.0.0.0:11111')
  server.handle(MyServer.new)
  server.run
end

main

こんな感じ。クライアントであれば

#!/usr/bin/env ruby

require 'grpc'
require 'customer_service_services'

def main
  stub = Proto::CustomerService::Stub.new('localhost:11111')
  if ARGV.size == 2
    stub.add_person(Proto::Person.new(nameARGV[0], ageARGV[1].to_i))
  else
    stub.list_person(Proto::RequestType.new).each do |x|
      puts "name=#{x.name}, age=#{x.age}"
    end
  end
end

main

こんな感じに実装して下さい。今回は Sync サーバで実装しましたが、Async サーバで実装する場合は customers に排他を行うべきです。

C++ もやり方は変わりません。

protoc --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_ROOT)/bins/opt/grpc_cpp_plugin customer_service.proto

protoc でスタブを吐いてサーバであれば

#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <grpc/grpc.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc++/status.h>
#include <grpc++/stream.h>
#include "customer_service.pb.h"

using namespace proto;
using namespace grpc;

class CustomerServiceImpl final : public CustomerService::Service {
private:
  std::vector<Person> customers;
public:
  Status AddPerson(ServerContext* context, const Person* customer, ResponseType* response) {
    std::cout << "AddPerson" << std::endl;
    customers.push_back(*customer);
    std::cout << "Done" << std::endl;
    return Status::OK;
  }

  Status ListPerson(ServerContext* context, const RequestType* request, ServerWriter<Person>* writer) {
    std::cout << "ListPerson" << std::endl;
    for (const Person& p : customers) {
      writer->Write(p);
    }
    std::cout << "Done" << std::endl;
    return Status::OK;
  }
};

int
main(int argc, char* argv[]) {
  grpc_init();
  std::string server_address("0.0.0.0:11111");
  CustomerServiceImpl service;

  ServerBuilder builder;
  builder.AddPort(server_address);
  builder.RegisterService(&service);
  std::unique_ptr<Server> server(builder.BuildAndStart());
  std::cout << "Server listening on " << server_address << std::endl;
  server->Wait();
  grpc_shutdown();
  return 0;
}
またクライアントであれば #include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <grpc/grpc.h>
#include <grpc++/channel_arguments.h>
#include <grpc++/channel_interface.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/status.h>
#include <grpc++/stream.h>
#include "customer_service.pb.h"

using namespace proto;
using namespace grpc;

int
main(int argc, char** argv) {
  grpc_init();
  std::unique_ptr<CustomerService::Stub> client = CustomerService::NewStub(
      grpc::CreateChannelDeprecated("127.0.0.1:11111", ChannelArguments()));
  ClientContext context;
  RequestType request;
  ResponseType response;
  Person person;

  Status status;
  if (argc == 3) {
    person.set_name(argv[1]);
    person.set_age(atoi(argv[2]));
    status = client->AddPerson(&context, person, &response);
  } else {
    std::unique_ptr<ClientReader<Person>> reader = client->ListPerson(&context, request);
    while (reader->Read(&person)) {
      std::cout << "name=" << person.name() << ", age=" << person.age() << std::endl;
    }
    status = reader->Finish();
  }
  if (!status.IsOk()) {
    std::cout << "ListFeatures rpc failed." << std::endl;
  }
  client.reset();
  grpc_shutdown();
}

この様に実装します。同じ proto ファイルから生成したサーバやクライアントですので、ruby のサーバを起動して、golang のクライアントや C++ のクライアントからリクエストを送る事も出来ますし、C++ をサーバや golang をサーバにしても良いでしょう。

ただ触った感じですが、ruby のサーバは何故かレスポンスが悪かったので調査を兼ねてベンチマークを取ってみました。

シナリオは、ruby、C++、golang それぞれのサーバを起動して C++ のクライアントから要求します。計測は AddPerson の1000回呼び出し、とその1000件入った状態で ListPerson を100回呼び出しを計測しました。

ruby

mattn/grpc-example-rb - GitHub

AddPerson

$ time seq 1000 | xargs -n 1 ./client mattn

real    0m14.287s
user    0m6.667s
sys     0m4.607s

ListPerson

$ time seq 100 | xargs -n 1 ./client > /dev/null

real    0m12.385s
user    0m4.833s
sys     0m4.367s

cpp

mattn/grpc-example-cpp - GitHub

AddPerson

$ time seq 1000 | xargs -n 1 ./client mattn

real    0m12.326s
user    0m6.007s
sys     0m4.710s

ListPerson

$ time seq 100 | xargs -n 1 ./client > /dev/null

real    0m4.304s
user    0m2.430s
sys     0m1.490s

golang

mattn/grpc-example - GitHub

AddPerson

$ time seq 1000 | xargs -n 1 ./client mattn

real    0m13.067s
user    0m6.553s
sys     0m4.737s

ListPerson

$ time seq 100 | xargs -n 1 ./client > /dev/null

real    0m5.755s
user    0m2.767s
sys     0m1.983s

とまぁ、想定通りの結果が出ました。golang が案外頑張ってるなーという印象です。今後時間が出来たら Java や python も触っていく予定です。これまで3言語を同じ proto ファイルからスタブ生成して開発を行ってみましたが、各々扱い方が異なるのでちょっと混乱する可能性があります。自分の好きな言語で実装するのが良いと思います。

サーバ/インフラ徹底攻略 (WEB+DB PRESS plus) サーバ/インフラ徹底攻略 (WEB+DB PRESS plus)
伊藤 直也, 片山 暁雄, 平山 毅, 舟崎 健治, 吉荒 祐一, 今井 雄太, 八木橋 徹平, 安川 健太, 宮下 剛輔, 田中 慎司, 久保 達彦, 道井 俊介, 飯田 祐基, 桑野 章弘, 松浦 隼人, 中村 俊之, 福永 亘, 杉山 仁則, WEB+DB PRESS編集部
技術評論社 大型本 / ¥44 (2014年10月30日)
 
発送可能時間:

WEB+DB PRESS Vol.85 WEB+DB PRESS Vol.85
菅原 元気, 磯辺 和彦, 山口 与力, 澤登 亨彦, 濱田 章吾, 宮田 淳平, 松本 亮介, 海野 弘成, 佐藤 歩, 泉水 翔吾, 佐藤 太一, hide_o_55, 青木 良樹, 武本 将英, 道井 俊介, 伊藤 直也, 橋本 翔, 渡邊 恵太, 舘野 祐一, 中島 聡, はまちや2, 竹原, 牧 大輔, 工藤 春奈, WEB+DB PRESS編集部
技術評論社 大型本 / ¥1 (2015年02月24日)
 
発送可能時間:

Posted at by