特定のタグがついた記事
Pythonでマルチスレッドプログラミングする(マルチスレッディング)
2010/7/22 木 0:41:06 by Lotus
今回はPythonにおけるマルチスレッドプログラミングについて。
そもそもマルチスレッドとはなにかといいますと、スレッドという処理の塊の単位を複数に分けること。たとえばCPUのコアが2つなら(デュアルコアCPU)、そのコア一つ一つに処理を割り振ったり。
まぁ並行処理させたり。
その辺はプリエンプティブマルチタスクとか、ノンプリエンプティブマルチタスクの話が絡んでくるのであれだけど。
OSが管理するのがプリエンプティブマルチタスク。アプリケーション自体がタスク、CPUを管理するのがノンプリエンプティブマルチタスク。
メリットとして、
処理の待ち時間の節約。
ネットワーク絡みの処理だとレスポンスまでに時間がかかってその間に処理をおこなう。
複数の処理を並列して行う。
など、メリットがある。リソースの有効な使い方ができる。
今回はそのマルチスレッドプログラミングをPythonで実装する。
Pythonのマルチスレッド機能は、OSのスレッド機能と密接に動くため、オーバヘッドが少ない。
Pythonにおけるマルチスレッドを行うにはthreadingモジュールのThreadクラスを継承すると簡単。他にもthreadingモジュールがある。(threadモジュールのthreadingとは別。)
threadingモジュールに定義されているThreadクラスがスーパークラスで、自分が作成するクラスはそれを継承したサブクラスになる。
このサブクラスではrun()というメソッド(関数)をオーバーライドする。
オーバーライドとはサブクラスでメソッドを再定義すること。書き換えるみたいな感じ。
__init__()メソッドも必要があるならオーバーライドする。初期化とか。
Threadの__init__()メソッドを継承しないとstart()とか使えない。
なお、run()メソッドは直接インスタンスから指定し実行うするのではなく、インスタンスからstart()メソッドを呼び出す。
そうすることで直接ではなく、間接的にrun()で定義した処理を行うことができる。直接run()を呼び出してはいけないみたい。
直接呼び出すと、プロンプトが戻らない(制御きかない。)
今回私はマルチスレッドを活かすため、ネットワークプログラミングにPythonのマルチスレッディングを使用した。
ネットワークプログラミングといっても簡単なもので、Socket通信による簡単なチャットシステム。
一つのスレッドでは処理をまっていないと(listen)いつ相手からメッセージがくるかわからない。
listenしながらも様々な処理を行うためにはどうしてもマルチスレッドを利用せざるを得ない…かも。
import socket from threading import Thread,Lock import thread import sys class SocketServer(Thread,object): def __init__(self): #super class init Thread.__init__(self) #socket settings self.s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) self.s.settimeout(1000) self.while_count = 0 self.while_flag=True self.data=[] #port number options if "-p" in sys.argv[1:]: self.port = sys.argv[sys.argv.index("-p")+1] try : self.port=int(self.port) except : print "Error! Port number is integer." sys.exit() #Default port number = 7777 else : self.port = 7777 #Main Thread. def run(self): print "=" * 50 print "Start the server program." print "Listening at : %s" % self.port print "=" * 50 print "Pending connections..." try: self.s.bind(('',self.port)) self.s.listen(10) except : print "Network error." print "Is the port number is already being used?" sys.exit() #While get recv while self.while_flag: self.conn,self.addr = self.s.accept() #print connect to if self.while_count == 0: print "Connected by %s " % self.addr[0] self.while_count=1 else : pass try : self.data=self.conn.recv(1024).encode("utf-8") self.conn.send("OK") if self.data == "exit": print "%s is closed the connection" % self.addr[0] self.data="=== Withdrawal ===" self.conn.close() except : print "Failed recv." self.conn.close() try : if len(self.data) !=0: print "-" * 50 print "%s => %s" % (self.addr[0],self.data) self.conn.close() except : pass self.conn.close() #Send to argument. def send(self,val): try : self.conn.send(val+"\n") except : print "Error! one more please." #Thread stop method def stop(self): self.while_flag=False try: print "wait..." self.conn.send("Please enter a space , charcter. exsample => [bye].") except: print "Please enter a space , charcter or a client" self.conn.close() print "Connection will be closed"
上記はSocket通信を使ったスレッドの例。
これだけではあまり意味をなさないが、上記の処理をバックグラウンド、というよりスレッドとして後ろで動くので、ネットワーク特有の処置待ちをしないですむ。
このプログラムは、Socket通信をする際、サーバとなるスレッド。
未完成だが、Clientがパケットを送信してくると、サーバのプロンプトにIPアドレスと送られてきた内容を表示する、など簡単なプログラムが組んである。
今、このマルチスレッディングの技術をつかって、開発中なので、また数日し、完成したらここにアップしようかと。
Pythonでbit.lyのAPIを使用する
2010/5/16 日 7:17:23 by Lotus
TwitterなどでURLを含んだ内容をPostするときに、URLを短縮してくれる事で有名なbit.lyのAPIをPythonで使う方法。
bit.lyのPythonモジュール
ダウンロードしたbitly.pyをimportできるようにするためにsites-packages直下に置く
bitly.pyだけで動作する。
自分の環境はusr/local/lib/python2.6/site-packagesだったので、wget でそのディレクトリにダウンロードすることで利用可能になった。
使い方としては、まずはbit.lyに登録する。
登録したらツールのBit.ly API Creadentialsを選択し、API Keyを取得する
簡単な使い方を下記に示す。
import bitly url="http://lotus-network.net" bitly=bitly.Api=(login="ユーザ名",apikey="取得したAPIKey") short_url=bitly.shorten(url) print short_url
これで簡略化されたURLが返ってくる。
Pythonのインタラクティブシェルでclearを使う
2010/5/16 日 6:22:58 by Lotus
pythonのインタラクティブシェルで色々作業していると下にたまっていて見にくい。
Linuxなどのターミナルだとclearと入力することで画面がキレイにクリアできる。
Pythonのインタラクティブシェルでも使いたいので、defで簡単に定義し、使用してみた。
import os def clear(): os.system("clear)
以上。
osモジュールを読みこみosコマンドであるclearを使うだけ
シェルの中では
clear()
と入力すれば画面がクリアされる。便利(?)
Ctrl+Lでできるそうです(泣)
自分のブログが更新されるとtwitterに自動でPOSTするプログラム
2010/4/6 火 14:02:29 by Lotus
lotusです。
題名の通り書いてみました。
以前RSSを読み取ってメール送信するプログラムを書いたのですが、かなりソースを使い回すことができました。
流れは
ブログのRSSを読み取る→txtとして変更点を保存→新しい更新をtxtに保存→双方が違ったならtwitterにポスト
多分もっと賢いやり方ありますけど、自分には考えつかなかったのでこんな方法です。
!/usr/bin/env python # -*- coding:utf-8 -*- import feedparser import codecs import twitter #RSS parse d=feedparser.parse("http://lotus-network.net/?feed=rss2") e=d.entries blog_url=e[0].link title=e[0].title #date logfile is open&write fo=codecs.open("/home/lotus/python/my_blog.txt","r","utf-8") old=fo.read() new=e[0].title fo.close() #write fo=codecs.open("/home/lotus/python/my_blog.txt","w","utf-8") fo.write(e[0].title) fo.close() #Post Twitter def twitter_post(old,new): api=twitter.Api("lotus_net","パスワード") sp=" " if (old!=new): api.PostUpdate(u"[ブログ更新]"+title+sp+blog_url+sp+" - Lopps - ") print "Post Success" else : print "Pass" pass twitter_post(old,new)
これだけです。fromAPIとなりますが、Oauthとかめんどいので、このまま放置で。
あとはcronで回すだけ、更新あると勝手にポストしてくれます。
cronの頻度は自分がどれくらい更新するかというので決めてください(笑
Pythonでプログラミング時に便利なツール&プラグイン
2010/4/6 火 5:30:45 by Lotus
おはこんばんちは、lotusです。
題名の通り、Pythonでプログラミングする際に、「あったら便利だなー」というものを紹介したいと思います。
なお、実際に動かしたのはLinux環境です。
Windowsをお使いの方では環境の違いなどから多少違った操作をおこなわなければいけない可能性が ありますが、ご了承ください。
記事に画像が使われておりますが、クリックすることで拡大可能です。
では、通常のインタラクティブシェルを拡張、改良したとも言える「IPython」を紹介したいと思います。
IPythonとは何か
上記にもある通り、インタラクティブシェル(対話コンソール)を拡張したものです。
通常のインタラクティブシェルでは、文字の補完などができませんが、この「IPython」では文字の補完の他にも、インタラクティブシェルには無かった機能が盛り込まれています。
IPythonは、WindowsでもLinuxでも動作しますので、是非インストールすることをオススメします。
自分のLinux環境(使用したのはDebian GNU/Linux)では、リポジトリにIPythonがあったので、apt-getコマンドで以下のように入手することが可能です。
sudo apt-get update
sudo apt-get upgrade
sudo apt-get -y install ipython
これでipythonコマンドが使える状態になります。
Windowsをお使いの方はコチラでファイルをダウンロードし、インストールしてください。
Macでも使用可能みたいですが、よく調べてないのでわかりません、すいません><
実際に使ってみた画面です。
これは、ipythonコマンドでIPythonを起動し、簡単なプログラムを書いた例です。
print (”HelloIPython”)※
HelloIPython
IPythonでも、通常のインタラクティブシェルでも同じ構文で正しく動作しているのがわかります(当たり前
※printの()は無くても動作します
エラーもわかりやすく、カラーをつけて出力してくれますね。
画像編集ミスって肝心な所を消してしまったのですが(上記の拡大してある画像には書いてあるが)
これは文字列と数字を足そうとしているためにTypeErrorとなってしまっています。
print (“Hello IPython “+str(i))
range(5)、つまり0,1,2,3,4がiのなかに入っているわけですが、それを数値ではなく、文字列とすることでこのTypeErrorを解決しています。
なお、このIPythonには通常のインタラクティブシェルとは違い、In[1]とかIn[2]とか行ごとにInのなかが変わっていきます。
普通のインタラクティブシェルと同じ表示にすることも可能です。
IPythonを起動する、ipythonコマンドに、オプションをつけることで可能です。
ipython -cl
と、-clオプションをつけると、通常の表示になります。
起動させてみた画面はこちらです。
行ごとにあったIn[1]などが消え、見覚えのある「>>>」になっています。
IPythonでは文字の補完ができる
LinuxやUNIXのシェルでは、文字の補完がTabキーでできますよね。
そのようにIPythonでは文字の補完をすることが可能です。
この例は、キーボードから「i」という文字だけを入力し、Tabキーを押した例です。
このような感じで補完することができますので、長いモジュール名をいちいち入力しなくてもTabキーを押して補完なんてことができます。
IPythonでは簡単なUNIXコマンドが使える
通常のインタラクティブシェルではPythonとの対話ができるわけですが、UNIXコマンドは使えません。
上の画像のように、「ls」や「mkdir」をインタラクティブシェルで入力すると、NameError、そんなものはないと言われ、エラーが発生します。
しかし、IPythonでは「簡単」なUNIXコマンドなら使う事ができます。
たとえば「今カレントディレクトリどうなってたっけ?」「あのディレクトリもうつくったっけ?」などなど。
通常ですと、窓を他に立ち上げるか、一回インタラクティブシェルを閉じるかなどの処理おこなわないと、こういったことはできません。
インタラクティブシェルを一旦閉じるなどすると、インタラクティブシェル内でつかっていた変数などは全てリセットされてしまいます。
実際にIPythonでUNIXコマンドを使ってみた画面が以下です。
このように、「ls」や「pwd」、「cd」、「pwd」などのUNIXの基本的なコマンドを使う事が可能です。
なので、たとえば「テキストファイルをあるディレクトリ出力する際、ディレクトリを作ってなく、エラーがでる」
なんて時はmkdirでIPython上で作成してあげれば言い訳です。
他にもログモードなど、便利な機能がありますので、是非調べてみてください。
便利なIPython、使ってみてはどうでしょうか?
次に、PythonでVimを使ってプログラミングする際に便利なプラグインを紹介したいと思います。
VimとはWindowsでいう「メモ帳」のようなエディタです。
LinuxやUNIX系では、VimやEmacsのようなエディタを使ってプログラミングする事が多いと思います。
Vimでは、プラグインと呼ばれる拡張プログラムを追加することにより、Vimの機能を便利にしたりすることができます。
今回はPydictionというVimプラグインを紹介します。
以下が実際に動作している画面です。
ピンクの場所に補完項目がでているのが確認できます。
Pydictionとは
Pydictionは、vimでpythonのプログラムをする際に、モジュールなどを補完してくれる機能をもったプラグインです。
Pythonをvimで書く!という人は、是非導入すべきプラグインです。
ダウンロードはコチラのページからzip形式でダウンロードすることが可能です。
現在(2010/4/6)では、1.2が最新版のようです。
Windowsでの動作は確認していないのでわかりません、すいません。。。
Linuxではwgetコマンドをつかい、DLしたのですが、なぜかうまくいきませんでしたので(自分の環境では)ブラウザから先ほどのダウンロードページにいき、ダウンロードしました。
zip形式なので、unzipコマンドによって解凍することが可能です。
解凍し、ディレクトリに移動すると
pydiction.vim
pydiction.py
complete-dict
README.txt
以上の四つのファイルが出力されます。
README.txtは良いとして、各ファイルの説明です。
pydiction.vim はvimのプラグインの本体になります。
pydiction.py は拡張子の通り、pythonのスクリプトであり、このスクリプトで辞書(補完にでてくる項目)をカスタマイズすることが可能です。
complete-dic tは、補完の項目が記されています。
ではディレクトリに配置していきます。
プラグインの本体である、pydiction.vimはユーザのホームディレクトリに位置する、「.vim」という.からはじまる隠しフォルダ?のなかに入れておけばOKです。
mkdir ~/.vim/plugin
mv pydiction.vim ~/.vim/plugin
これでpydiction.vimをディレクトリの.vimディレクトリに移動しました。
次にcomplete-dicですが、辞書ファイルなので、どこのディレクトリに配置してもかまわないのですが、わかりやすさなどの面をみて、.vimに配置しましょう。
mkdir ~/.vim/pydiction
mv complete-dic ~/.vim/pydiction
これで辞書ファイルを配置しました。
最後にpydictionですが、これもcomplete-dicと同じ場所に配置しましょう。
mv pydiction.py ~/.vim/pydiction
これでディレクトリに配置する作業は終了です。
このpydictionをvimで正しく使える状態にするためにホームディレクトリ直下に位置する.vimrcを編集します。
autocmd FileType python let g:pydiction_location = ‘~/.vim/pydiction/complete-dict’
上位のコードをvimrcのなかに追加することで、pydictionが正しく動作します。これは辞書ファイルの位置を指定しています。
使い方としては直感的に使えると思います。
ある程度文字を打った後に、Tabキーで補完することが可能です。
とても便利なプラグインです。
pydiction、つかってみてはどうでしょう。
そして最後の紹介になりますが、vimrcに追加するとpythonプログラミングが楽になるコードを紹介します。
それはvim上で、pythonを実行するという物。というより見せかけるだけなのですが。
インタラクティブシェルでやればそのまま実行できますが、vimでソースを書いて実行するには、
普通は:wqなどで保存、終了してから実際にプログラムをたたくということになります。
ですが、以下のコードを.vimrcに追加することでvim上でpythonのソースを実行させることができます。
” Execute python script C-P
function! s:ExecPy()
exe “!” . &ft . ” %”
:endfunction
command! Exec call <SID>ExecPy()
autocmd FileType python map <silent> <C-P> :call <SID>ExecPy()<CR>
これでpythonがvimで実行できるようになります。
C-Pなので、CtrlとPを押すことによって実行できます。
実際に実行してみた画面がこちら。
ソースは
print “Hello Python”
[最後の変更が保存されていません]とあります。
これは一旦ファイルを保存しないと動きませんので、注意です。
開いた状態でCtrl+Pを押すことにより上の画像のような出力を得られます。
ENTERを押すことによりvimに戻れるので、ソースを確認するにはかなり便利なコードですね。
是非使ってみてください。
「Pythonでプログラミング時に便利なツール&プラグイン」でした。
以上lotusでした、長文かなり疲れました。脱字とかありそうです。
あったらコメントなりよろしくおねがいします。
[Python]簡単にメール送信するプログラム
2010/4/3 土 7:01:56 by Lotus
ろーたすです。
pythonでメール送信するプログラムは結構前につくって、使用してたのですが、簡単に送信するプログラム書いてみた。
作った理由は、
携帯でメールするのだるい
簡単なメールなのにwebからいちいちするのだるい
結果:CUI、てか端末で送信できるようにしちまえば楽ちん
とまぁこのような感じです。
Linuxなら動くと思います。Windowsでは確認してない
実際にソースさらします。汚いですゴミです。
#!/usr/bin/env python # -*- coding:utf-8 -*- import os import time import smtplib from progressbar import * from email.MIMEText import MIMEText from email.Header import Header from email.Utils import formatdate def bar(): print "-"*30 widgets = ["Send: ", Percentage(), Bar()] maxval = 250 pbar = ProgressBar(maxval=maxval, widgets=widgets).start() for i in range(maxval): time.sleep(0.001) pbar.update(pbar.currval + 1) pass pbar.finish() def choice(): print "*"*30 print "Please choice number!" print "1: hoge@docomo.ne.jp" print "2: hoge@gmail.com" print "3: other" print "*"*30 to=raw_input("") if(to=="1"): to="hoge@docomo.ne.jp" mail_send(to) elif(to=="2"): to="hoge@gmail.com" mail_send(to) elif(to=="3"): to=raw_input("Please input mail address==") mail_send(to) else: os.system("python /home/lotus/python/mail.py") def mail_send(to): from_addr = 'myaddress@gmail.com' to_addr = to #Raw_input subject=raw_input("Subject?==") subject=subject.decode("utf-8") body=raw_input("Body?==") body=body.decode("utf-8") bar() #mail settings encoding="utf-8" msg = MIMEText(body.encode("utf-8"),'plain',encoding) msg['Subject'] = Header(subject, encoding) msg['From'] = from_addr msg['To'] = to_addr msg['Date'] = formatdate() s = smtplib.SMTP('smtp.gmail.com', 587) s.ehlo() s.starttls() s.ehlo() s.login('myaddress@gmail.com', 'passwd') s.sendmail(from_addr, to_addr, msg.as_string()) s.close() print "-"*30 choice()
この場合、件名がtesutoになり、本文が「日本語も使えますよ」というメールがhoge@docomo.ne.jpに送信されます。
モジュールを色々importしているので、はいってなかったら入れれば動きます。
えー、なにをしているかですが、おおざっぱに
import os import time import smtplib from progressbar import * from email.MIMEText import MIMEText from email.Header import Header from email.Utils import formatdate
このあたりはいいですよね、必要なモジュール類をimportしています。はい
def bar(): print "-"*30 widgets = ["Send: ", Percentage(), Bar()] maxval = 250 pbar = ProgressBar(maxval=maxval, widgets=widgets).start() for i in range(maxval): time.sleep(0.001) pbar.update(pbar.currval + 1) pass pbar.finish()
defでbar()関数というものを作っております。
これは単なる演出なのですが、プログレスバーを出す処理。
progressbarモジュールというものがあり、それをimportすることにより実装可能です。
def choice(): print "*"*30 print "Please choice number!" print "1: hoge@docomo.ne.jp" print "2: hoge@gmail.com" print "3: other" print "*"*30 to=raw_input("") if(to=="1"): to="hoge@docomo.ne.jp" mail_send(to) elif(to=="2"): to="hoge@gmail.com" mail_send(to) elif(to=="3"): to=raw_input("Please input mail address==") mail_send(to) else: os.system("python /home/lotus/python/mail.py")
choice関数をつくりました。
これも単純すぎる関数(笑
printはどうでも良いとし、if分でtoにはいっている文字列を・・・という処理をし、選択にあったメールアドレスをtoに代入しています。
このなかで注目すべき点といっては何ですが、elseで例外処理をしています。
この場合、os.systemというOSのコマンドが実行できるもので、python 略 /mail.pyという自分自身のコードを指定することにより、1,2,3でもなければもう一回起動するという形になります。
最後の関数ですが
def mail_send(to): from_addr = 'myaddress@gmail.com' to_addr = to #Raw_input subject=raw_input("Subject?==") subject=subject.decode("utf-8") body=raw_input("Body?==") body=body.decode("utf-8") bar() #mail settings encoding="utf-8" msg = MIMEText(body.encode("utf-8"),'plain',encoding) msg['Subject'] = Header(subject, encoding) msg['From'] = from_addr msg['To'] = to_addr msg['Date'] = formatdate() s = smtplib.SMTP('smtp.gmail.com', 587) s.ehlo() s.starttls() s.ehlo() s.login('myaddress@gmail.com', 'passwd') s.sendmail(from_addr, to_addr, msg.as_string()) s.close() print "-"*30 choice()
mail_send、具体的にメール送信する関数です。
引数として、choice関数からのtoをもらいます。選択されたメールアドレスをもらうわけです。
#Raw_input subject=raw_input("Subject?==") subject=subject.decode("utf-8") body=raw_input("Body?==") body=body.decode("utf-8") bar()
このあたりで、件名と本文の入力を受け付け、decodeします。(日本語だとエラーがでるために)
そしてbar()で先ほどのプログレスバーを表示させます。(実際には意味がまったくなく、飾り(笑
s = smtplib.SMTP('smtp.gmail.com', 587) s.ehlo() s.starttls() s.ehlo() s.login('myaddress@gmail.com', 'passwd') s.sendmail(from_addr, to_addr, msg.as_string()) s.close()
このあたりで、SMTPによる認証をします。SMTPとは簡単に言えばメールを送信するためのプロトコルです。
この場合、myaddress@gmail.com、パスワードがpasswdでgmailにログインし、sendmailします。
そして最後に接続をclose。
しかし、これらは関数を定義しただけですので、実行されません。
なので、インデントから抜けchoice()を実行することによりメールが送信されます。
choice関数にはsend_mail()を引数ありで呼び出しているので、単体?でsend_mail()を呼び出す必要がありませんし、単体で呼び出すとエラーがでます(メールアドレスの指定)
解説とは言えないほどのものでしたが、このような感じで簡単に端末からメールを送信することが可能です。自分専用に書いた物なので必要性ないとおもいますが、w
RSSがないページをPythonで処理し、メールを送信する。
2010/1/27 水 5:18:38 by Lotus
Lotusです。
このプログラムは自分がほしい!とおもったので作ってみました。
なにをするかといいますと、題名の通りです。
RSSがないため毎日毎日チェックしなければいけなかったのですが、今回このプログラムを作ったのでいちいちブラウザでみなくてもメールを見ることができます。
ソースは↓
#!/usr/bin/env python # -*- coding:utf-8 -*- import feedparser #RSS parse d=feedparser.parse("http://page2rss.com/rss/hogehoge") e=d.entries #date logfile is open&write fo=open("date.txt","r") old=fo.read() old=old.split() new=e[0].date new=new.split() fo.close() #write fo=open("date.txt","w") fo.write(e[1].date) fo.close() #mail send def mail_send(): import smtplib from email.MIMEText import MIMEText from email.Header import Header from email.Utils import formatdate from_addr = 'lotus.ner@gmail.com' to_addr = 'n@googlegroups.com' subject = u'更新のおしらせ。' body = e[0].date+u"""に更新しました """+e[0].title encoding = 'utf-8' msg = MIMEText(body.encode("utf-8"),'plain',encoding) msg['Subject'] = Header(subject, encoding) msg['From'] = from_addr msg['To'] = to_addr msg['Date'] = formatdate() s = smtplib.SMTP('smtp.gmail.com', 587) s.ehlo() s.starttls() s.ehlo() s.login('lotus.ner@gmail.com', 'hogehoge') s.sendmail(from_addr, to_addr, msg.as_string()) s.close() #day different if new[1] != old[1]: mail_send() #day same elif new[1]==old[1]: #time different if new[4] != old[4]: mail_send()
70行くらいですかね。pythonです。
feedparseでhttp://page2rss.comのものをいじってます。
んで、gmailにログインし、メーリングリストに送信します。
流れはパースしてから、その更新した日にちをまずdate.txtとしてテキストに保存します。
そして、新しく更新されたかチェック(厳密に言うと違うが)し、date.txtと比較します。
もしも同じ日にちだった場合、そこで切り捨てずに時間をみくらべて、違うならメール送信。
違う日にちならそっこうメール送信です。
3.4時間かかったのは内緒
実際に運用してますがなんのメーリングリストかは秘密です。しらべまくればわかるかも。w
# -*- coding:utf-8 -*-








