2009/07/22

epoll recv

Twisted が分からないのもそのはずで
やはり非同期ってのが良く分かっていないからなのでした
Twisted ドキュメント: Twisted による非同期プログラミング
ってのを twisted tutorial deferred で教わって
そもそも英文の方も読んだはずなのにちゃんと分かってなかったみたい

で、select とか epoll とかいう単語を
Voluntas さんに教えて頂くなどしまして
ちょっくら自分でも何か書いてみるかということで
RSS とか Atom とか取ってきてみようかなと
途中で悩んでググってみて
How epoll detect clientside close in Python? - Stack Overflow
のコードとか見たりしつつ

で、実際やってみたら HTTP の処理が面倒になっちゃったんで
まぁとりあえず epoll だけ実感できる感じで
from socket import socket, gethostbyname, error
from select import epoll, EPOLLIN, EPOLLOUT
from urlparse import urlparse

FEEDS = (
'http://d.hatena.ne.jp/Voluntas/rss2',
'http://kamo.typepad.jp/blog/index.rdf',
'http://takagi-hiromitsu.jp/diary/index.rdf',
'http://d.hatena.ne.jp/nishiohirokazu/rss2',
'http://www.nnar.org/feed/atom',
'http://d.hatena.ne.jp/CortYuming/rss2,'
'http://vim-users.jp/feed/atom/',
'http://blog.livedoor.jp/dankogai/atom.xml',
'http://d.hatena.ne.jp/Chikirin/rss',
'http://thisistanaka.blog66.fc2.com/?xml',
)

ep = epoll(1024)
sockets = []
feeds = {}

for feed in FEEDS:
feed_data = urlparse(feed)
hostname = feed_data.netloc
path = feed_data.path
s = socket()
s.settimeout(0)
try:
s.connect_ex((hostname, 80))
except:
continue

fileno = s.fileno()
feeds[fileno] = (hostname, path, s)
ep.register(fileno, EPOLLOUT)

while feeds:
for (fileno, event) in ep.poll():
s = feeds[fileno][2]
if event == EPOLLOUT:
s.send("GET %s HTTP/1.1\nHOST: %s\n\n" %
(feeds[fileno][1], feeds[fileno][0]))
ep.modify(fileno, EPOLLIN)
elif event == EPOLLIN:
s.setblocking(1)
print s.recv(1024)
del feeds[fileno]
ep.unregister(fileno)
実行する度に結果が違うはずで
それは返事が来た順番で処理できてるからなはず

FEEDS の分だけ socket 張って
epoll で監視して受けとれるようになった奴から 1KB だけデータ読んでます
Python の場合 socket object には connect_ex って method がありまして
こいつは exception ではなくて error の値を吐くんだそうです

が、connect_ex は接続先が resolve できなかったときだけ
exception 吐くという仕様となっていたので
結局 try except してしまいました

あと、ほんとは socket.fromfd とかで socket 呼んだ方がいいのかも
だけど別の場所で socket を覚えさせたりしないと
    ep.modify(fileno, EPOLLIN)
IOError: [Errno 9] Bad file descriptor
って言われたりして
unregister した瞬間に socket が葬り去られてしまってるんでしょうか
無駄に覚えさせといても動いたんですが折角なんで
socket も feeds の中に入れてみました
modify ってあったから使ってみたんだけどこれが間違ってる可能性もあり

で、更に recv するんじゃなくて socket を thread に渡したりすると
きっと凄い格好の良いことになるに違いありません
Twisted が何してるか少し分かったかも
Twisted の reactor は default だと selectreactor ってのが呼ばれてるけど
他にも色々、例えば epollreactor とかもあるみたいなので
それぞれ reactor 毎に色々してるに違いない、違いないんだけど.....

2 件のコメント:

  1. 一連の記事を見ていると、あなたに今足りないのは「勉強」じゃなくて「実践」の方じゃないかと思います。

    Twistedとかepollを使わない一般的な方法で、何か実用的なGUIプログラムでも書いてみては?簡単なチャットとか。

    そうすれば非同期処理がどのような場面で必要なのか、カラダでわかります。

    返信削除
  2. な、なるほど、実践できていませんでしたか...。
    GUI プログラムは書いたことが無いので
    良い機会を頂けたので今度挑戦してみようと思います。
    コメント頂きましてありがとうございます!!

    返信削除