ã¯ããã«
ãã®èšäºã§ã¯ãWebéçºã«Pythonã䜿çšããããšãšPHPã§Pythonã䜿çšããããšã®éãã«ã€ããŠè³ªåããŸãã ãã®èšäºãããªããŒã«ã€ãªãããªãããšãé¡ã£ãŠããŸããããã¯ãã©ã¡ãã®èšèªãè¯ããæªããã§ã¯ãªããPythonã®æè¡çç¹åŸŽã®ã¿ã«é¢ãããã®ã ããã§ãã
èšèªèªäœã«ã€ããŠå°ã
PHPã¯ãïŒèšèã®æå³ã§ïŒ æ»ã¬ããã«èšèšãããWebæåã®èšèªã§ã ã äœã¬ãã«ã®èŠ³ç¹ããèŠããšãPHPã¢ããªã±ãŒã·ã§ã³ã¯ãããããåäžã®ã»ãã³ãã£ãã¯ãšã³ããªãã€ã³ããæã€åå¥ã®ã¹ã¯ãªããã®ã³ã¬ã¯ã·ã§ã³ã«äŒŒãŠããŸãã
Pythonã¯æ±çšããã°ã©ãã³ã°èšèªã§ãããWebã§ã䜿çšã§ããŸãã æè¡çãªèŠ³ç¹ããèŠããšãPython Webã¢ããªã±ãŒã·ã§ã³ã¯ã¡ã¢ãªã«ããŒããããå®å šãªã¢ããªã±ãŒã·ã§ã³ã§ããããªã¯ãšã¹ãããšã«å éšç¶æ ãä¿åãããŸãã
äžèšã®æ©èœã«åºã¥ããŠãWebã¢ããªã±ãŒã·ã§ã³ã§ã®ãšã©ãŒåŠçã®éããç¶ããŸãã PHPã«ã¯ããšã©ãŒã®çš®é¡ïŒãšã©ãŒãäŸå€ïŒå šäœã®åç©åãããããããããååããããšã¯ã§ããŸãããã1ã€ã®ãªã¯ãšã¹ããåŠçãããŠããéãã¢ããªã±ãŒã·ã§ã³ã¯åç¶ãããããããïŒååã®äžå¯èœæ§ïŒã¯å®éã«ã¯éèŠã§ã¯ãããŸããã ãã£ãããããªããšã©ãŒã¯ãåã«ãã³ãã©ãŒããæ©æã«çµäºããã¡ã¢ãªããã¢ããªã±ãŒã·ã§ã³ãåé€ããã ãã§ãã æ°ãããªã¯ãšã¹ãã¯ãæ°ãããã¯ãªãŒã³ãã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠåŠçãããŸãã Pythonã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã¯åžžã«ã¡ã¢ãªå ã«ããããåèµ·åãããã«å€ãã®ãªã¯ãšã¹ããåŠçããŸãã ãããã£ãŠãã¢ããªã±ãŒã·ã§ã³ã®æ£ããäºæž¬å¯èœãªç¶æ ãç¶æããããšãéèŠã§ãã ãã¹ãŠã®ãšã©ãŒã¯æšæºã®äŸå€ã¡ã«ããºã ã䜿çšãããã£ããã§ããŸãïŒSyntaxErrorã®äŸå€ãé€ãïŒã äžæãªãšã©ãŒãçºçãããšãã¢ããªã±ãŒã·ã§ã³ãçµäºããå€éšããåèµ·åããå¿ èŠããããŸãã
Webçšã«PHPãšPythonãã調çãããæ¹æ³ã¯ãããããããŸãã 次ã«ãç§ãæãããç¥ã£ãŠãã2ã€ïŒæã人æ°ãããããã§ãïŒ -PHP + FastCGI ïŒ php-fpm ïŒãšPython + WSGI ïŒ uWSGI ïŒã«çŠç¹ââãåœãŠãŸãã ãã¡ããããããã®äž¡æ¹ã®ãã³ãã«ã®åã«ããã³ããšã³ããµãŒããŒïŒããšãã°ãNginxïŒãæ³å®ãããŠããŸãã
Pythonãã«ãã¹ã¬ãããµããŒã
ã¢ããªã±ãŒã·ã§ã³ãµãŒããŒïŒuWSGIãªã©ïŒãèµ·åãããšãPythonã€ã³ã¿ãŒããªã¿ãŒãã¡ã¢ãªã«èªã¿èŸŒãŸããWebã¢ããªã±ãŒã·ã§ã³èªäœãèªã¿èŸŒãŸããŸãã éåžžãã¢ããªã±ãŒã·ã§ã³ããŒãã¹ãã©ããã¢ãžã¥ãŒã«ã¯å¿ èŠãªã¢ãžã¥ãŒã«ãã€ã³ããŒãããåæååŒã³åºããè¡ããæçµçã«WSGIä»æ§ã«æºæ ããæºåæžã¿ã®åŒã³åºãå¯èœãªããžã§ã¯ãããšã¯ã¹ããŒãããŸãã ãåãã®ãšãããPythonã¢ãžã¥ãŒã«ãåããŠã€ã³ããŒããããšãäœæãããŠå€ã§åæåãããå€æ°ãå«ããã¢ãžã¥ãŒã«å ã®ã³ãŒããå®è¡ãããŸãã 2ã€ã®é£ç¶ããHTTPèŠæ±ã®éã§ã¯ãã€ã³ã¿ãŒããªã¿ãŒã®ç¶æ ã¯ãªã»ãããããªããããã¢ãžã¥ãŒã«ã¬ãã«ã®ãã¹ãŠã®å€æ°ã®å€ãä¿åãããŸãã
äžèšãäŸã§æ確ã«ç€ºãæãåçŽãªWSGIã¢ããªã±ãŒã·ã§ã³ãäœæããŸãããã
n = 0 def app(env, start_response): global n n += 1 response = "%.6d" % n start_response('200 OK', [('Content-Type', 'text/plain')]) return [bytes(response, 'utf-8')]
ããã§ã nã¯ã¢ãžã¥ãŒã«å€æ°ã§ããã次ã®ã³ãã³ãã䜿çšããŠã¢ããªã±ãŒã·ã§ã³ãã¡ã¢ãªã«ããŒããããšãå€0ã§äœæãããŸãã
uwsgi --socket 127.0.0.1:8080 --protocol http --single-interpreter --processes 1 -w app:app
ã¢ããªã±ãŒã·ã§ã³èªäœã¯ãããŒãžã«å€æ°nã®å€ã衚瀺ããã ãã§ãã å ¥å¿µãªPHPããã°ã©ããŒã«ãšã£ãŠã¯ãããŒãžã«ã000001ããšããè¡ããæ¯åã衚瀺ããå¿ èŠããããããæå³ããããŸããã
ãã¹ãããŠã¿ãŸãããïŒ
ab -n 500 -c 50 http://127.0.0.1:8080/ curl http://127.0.0.1:8080
ãã®çµæãè¡"000501"ãååŸããŸããããã¯ãã¢ããªã±ãŒã·ã§ã³ãuwsgiã¡ã¢ãªã«ããŒãããããªã¯ãšã¹ãéã§ãã®ç¶æ ãä¿æããŠãããšãã䞻匵ã確èªããŸãã
--processes 2ãã©ã¡ãŒã¿ãŒãæå®ããŠuWSGIãå®è¡ããåããã¹ããå®è¡ãããšãcurlãäœåºŠãåŒã³åºããšã2ã€ã®ç°ãªãæé ã·ãŒã±ã³ã¹ãæ¢ã«ããããšãããããŸãã abã¯500åã®ãªã¯ãšã¹ããéä¿¡ããããããããã®çŽååã¯1ã€ã®uWSGIããã»ã¹ã«ãæ®ãã¯2çªç®ã®uWSGIããã»ã¹ã«åé¡ãããŸãã curlã«ãã£ãŠè¿ãããæåŸ å€ã¯ãããã"000220"ããã³"000280"ã§ãã Pythonã€ã³ã¿ããªã¿ã¯ãæããã«ããã»ã¹ããšã«1ã€ã§ããã2ã€ã®ç¬ç«ããç°å¢ãšãªã¯ãšã¹ãã®å®éã®äžŠååŠçïŒãã«ãã³ã¢ããã»ããµã®å ŽåïŒããããŸãã
Pythonã¯ãèšèªã®äžéšãšããŠã¹ã¬ããããµããŒãããŠããŸãã åŸæ¥ã®å®è£ ïŒCPythonïŒã¯ãã€ãã£ãOSã¹ã¬ããã䜿çšããŸããã GILããããŸã-äžåºŠã«å®è¡ãããã¹ã¬ããã¯1ã€ã ãã§ãã ãã®å Žåãn + = 1ã§ããã¢ãããã¯æäœã§ã¯ãªãããã競åç¶æ ã®åé¡ãäŸç¶ãšããŠçºçããå¯èœæ§ããããŸãã
Pythonã³ãŒããéã¢ã»ã³ãã«ããŸã
WSGIã¢ããªã±ãŒã·ã§ã³ããéã¢ã»ã³ãã«ãããŸãã
ããã°ã©ã ã®å¢åã«ã¯4ã€ã®æäœãå¿ èŠã§ããããšãããããŸãã GILã®äžæã¯ããããã®ãããã§ãçºçããå¯èœæ§ããããŸãã
import dis n = 0 def app(env, start_response): global n n += 1 return [bytes(str(n), 'utf-8')] if '__main__' == __name__: print(dis.dis(app))
8 0 LOAD_GLOBAL 0 (n) 3 LOAD_CONST 1 (1) 6 INPLACE_ADD 7 STORE_GLOBAL 0 (n) 10 10 LOAD_GLOBAL 1 (bytes) 13 LOAD_GLOBAL 2 (str) 16 LOAD_GLOBAL 0 (n) 19 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 22 LOAD_CONST 2 ('utf-8') 25 CALL_FUNCTION 2 (2 positional, 0 keyword pair) 28 BUILD_LIST 1 31 RETURN_VALUE
ããã°ã©ã ã®å¢åã«ã¯4ã€ã®æäœãå¿ èŠã§ããããšãããããŸãã GILã®äžæã¯ããããã®ãããã§ãçºçããå¯èœæ§ããããŸãã
HTTPãªã¯ãšã¹ããã³ãã©ã®ã³ãŒãã«IOã®æåŸ ããªããšãã«ã¹ã¬ããã®æ°ãå¢ãããŠããåŠçã¯é«éã«ãªããŸããïŒãã ããã¹ã¬ããã¯ã³ã³ããã¹ããåãæ¿ããããšã§ãããã·ã¥ãã§ãããããé床ãäœäžããŸãïŒã GILã®å¶éã«ãããã¹ã¬ããã¯å®éã®äžŠååŠçãäœæããŸããããã°ãªãŒã³ã¹ã¬ããã§ã¯ãªããå®éã®OSã¹ã¬ããã§ãã
å¥ã®ãã¹ããè¡ã£ãŠã¿ãŸãããã 1ã€ã®ããã»ã¹ã§uwsgiãå®è¡ããŸããããã®äžã«10åã®ãã³ãã©ãŒã¹ã¬ããããããŸãã
uwsgi --socket 127.0.0.1:8080 --protocol http --single-interpreter --processes 1 --threads 10 -w app:app
ãããŠãab 5000ã¢ããªã±ãŒã·ã§ã³ãªã¯ãšã¹ããå®è¡ããŸãã
ab -n 5000 -c 50 http://127.0.0.1:8080/
åŸç¶ã®curlã¯ãšãª127.0.0.1ïŒ8080ã¯ãå€ã5000以äžã®æé ã·ãŒã±ã³ã¹ã1ã€ãããªãããšã瀺ããŸãïŒç«¶åç¶æ ã®å Žåã¯5000æªæºã«ãªããŸãïŒã
ã¢ããªã±ãŒã·ã§ã³ã¢ãŒããã¯ãã£ã«å¯Ÿããèšèªã®åœ±é¿
åHTTPèŠæ±ã¯åå¥ã®ã¹ã¬ããã§åŠçãããŸãïŒããã»ã¹ã«ã¯å°ãªããšã1ã€ã®ã¹ã¬ããããããããããã»ã¹ã«ã€ããŠãåæ§ã§ãïŒã åæã«ãåã¹ã¬ããã¯ããã®ã©ã€ãã¿ã€ã ïŒçæ³çãªæ¡ä»¶äžã§ã¯uwsgiã¢ããªã±ãŒã·ã§ã³å šäœã®ã©ã€ãã¿ã€ã ãšäžèŽããïŒã®éãå€ãã®HTTPãªã¯ãšã¹ããåŠçãããªã¯ãšã¹ããããªã¯ãšã¹ããžã®ç¶æ ïŒã¢ãžã¥ãŒã«ã¬ãã«å€æ°ã®å€ïŒãä¿åããŸãã ããã¯ãPHPã§HTTPãªã¯ãšã¹ããåŠçããããã®ã¢ãã«ãšã®äž»ãªéãã§ããPHPã§ã¯ãåãªã¯ãšã¹ãã«ã¯æ°ããåæåãããã°ããã®ç°å¢ããããæ¯åã¢ããªã±ãŒã·ã§ã³ãå床ããŒãããå¿ èŠããããŸãã
倧èŠæš¡ãªPHP Webã¢ããªã±ãŒã·ã§ã³ã§ã®äžè¬çãªã¢ãããŒãã¯ã Dependency Injection Containerã䜿çšããŠãåæåãšã¢ããªã±ãŒã·ã§ã³ãµãŒãã¹ã¬ãã«ãžã®ã¢ã¯ã»ã¹ãå¶åŸ¡ããããšã§ãã è¯ãäŸãPimpleã§ãã åHTTPãªã¯ãšã¹ãã®æåã®æé ã¯ãã³ã³ããå ã®å©çšå¯èœãªãã¹ãŠã®ãµãŒãã¹ãç»é²ããåæåã³ãŒããå®è¡ããããšã§ãã ããã«ãå¿ èŠã«å¿ããŠãã³ã³ãããŒã©ãŒã®ãµãŒãã¹ãªããžã§ã¯ãïŒé 延ïŒã«ã¢ã¯ã»ã¹ããŸãã åãµãŒãã¹ã¯ä»ã®ãµãŒãã¹ã«äŸåããå ŽåããããäŸåé¢ä¿ã¯ãµãŒãã¹éåäœã®åæåã³ãŒãå ã®ã³ã³ãããéããŠåã³è§£æ±ºãããŸãã
// $container['session_storage'] = function ($c) { return new SessionStorage('SESSION_ID'); }; $container['session'] = function ($c) { return new Session($c['session_storage']); }; // class MyController { public function __construct() { // get the session object $this->session = $container['session']; // "" , } }
ã³ã³ããã®ãããã§ããªããžã§ã¯ãã®1åéãã®äœæãšããµãŒãã¹ãžã®åŸç¶ã®åŒã³åºãããšã«æ¢è£œã®ãªããžã§ã¯ããè¿ãããšãã§ããŸãïŒå¿ èŠãªå ŽåïŒã ãã ãããã®éæ³ã¯åäžã®HTTPèŠæ±ã®ãã¬ãŒã ã¯ãŒã¯å ã§ã®ã¿æ©èœããããããµãŒãã¹ã¯èŠæ±åºæã®å€ã§ç°¡åã«åæåã§ããŸãã å€ãã®å Žåããã®ãããªå€ã¯ãçŸåšã®æ¿èªæžã¿ãŠãŒã¶ãŒãçŸåšã®ãŠãŒã¶ãŒã®ã»ãã·ã§ã³ãå®éã®HTTPãªã¯ãšã¹ããªã©ã§ãããªã¯ãšã¹ãã®çµäºæã«ãµãŒãã¹ã¯ç Žæ£ããã次ã®ãªã¯ãšã¹ãã®åŠçã®éå§æã«æ°ãããµãŒãã¹ãäœæããã³åæåãããŸãã ããã«ã1ã€ã®HTTPãªã¯ãšã¹ãã®åŠçãã¹ã¯ãªããã«å²ãåœãŠãããå¶éã«åãŸãå Žåãã¡ã¢ãªãªãŒã¯ã«ã€ããŠå®è³ªçã«å¿é ããããšã¯ã§ããŸããã
äžèšã®Pythonã¹ããªãŒã ã¢ãã«ãèæ ®ãããšãPython Webã¢ããªã±ãŒã·ã§ã³ã§åæ§ã®ã¢ãããŒãã䜿çšããããšã¯ãè¿œå ã®åªåãªãã§ã¯äžå¯èœã§ããããšãããããŸãã ã³ã³ãããã¢ãžã¥ãŒã«ã¬ãã«ã®å€æ°ïŒéåžžã«è«ççã«èŠããïŒã§ããå ŽåããµãŒãã¹ã¯è€æ°ã®HTTPãªã¯ãšã¹ããåŠçããè€æ°ã®ã¹ã¬ããéã®å ±æãªãœãŒã¹ã§ãããããå«ãŸãããã¹ãŠã®ãµãŒãã¹ãçŸåšã®ãªã¯ãšã¹ãã«åºæã®å€ã§åæåã§ããŸããã䞊è¡ããŠã äžèŠããã®åé¡ã«å¯ŸåŠããã«ã¯2ã€ã®æ¹æ³ããããŸãïŒçŸåšã®HTTPãªã¯ãšã¹ãããç¬ç«ãããµãŒãã¹ãªããžã§ã¯ããäœæããïŒãµãŒãã¹ã¡ãœãããžã®åŒã³åºãã¯äŸåãããŸãŸã§ãã¡ãœããã§äœ¿çšãããã¹ã¿ãã¯å€æ°ã¯å ±æãªãœãŒã¹ã§ã¯ãããŸããïŒããŸãã¯ã³ã³ãããã¹ããªãŒã ãªãœãŒã¹ã«ããããã»ã¹ïŒåã¹ã¬ããã¯ç¬ç«ããäžé£ã®ãµãŒãã¹ãšã®ã¿éä¿¡ããäžåºŠã«1ã€ã®ã¹ã¬ããã¯1ã€ã®HTTPèŠæ±ã®ã¿ãåŠçã§ããŸãïŒã
æåã®ã¢ãããŒãã®ãã©ã¹ã®ããã«æããŸã-ãµãŒãã¹ã¯uwsgiããã»ã¹ã®åç¶æéäžã«äžåºŠã ãåæåãããŸãã ãŸããã¡ã¢ãªãç¯çŽããããšãã§ããŸãïŒãã¹ãŠã®ã¹ã¬ããã«å¯ŸããŠ1ã»ããã®ãµãŒãã¹ãããªãããïŒã äžæ¹ãç¹å®ã®HTTPãªã¯ãšã¹ããåŠçããã«ã¯ãå©çšå¯èœãªãã¹ãŠã®ãµãŒãã¹ã®äžéšïŒã»ãšãã©ã®å Žåã¯å°ããïŒã®ãµãã»ããã®ã¿ãå¿ èŠã§ãã ã¢ããªã±ãŒã·ã§ã³ãååã«å€§ãããå°è±¡çãªæ°ã®ãµãŒãã¹ãæã£ãŠããå Žåãäžå®æ°ã®HTTPèŠæ±ãåŠçããåŸããµãŒãã¹ã®å€§éšåãåæåãããããã»ã¹ã¡ã¢ãªã«æ ŒçŽãããŸãã ããã¯æ·±å»ãªåé¡ã«ãªãããã§ãã
2çªç®ã®ã¢ãããŒãã¯ã threading.localã䜿çšããŠå®è£ ã§ããŸãã ãããã£ãŠãããšãã°ããã©ã¹ã³ãå°çããŸãã ã¢ãããŒãã説æããããã«ãããã€ãã®ã€ãã³ãã«ããŒã«ã«ã¹ããªãŒã ã¹ãã¬ãŒãžãå®è£ ã§ããŸãã
class EventsStore: def __init__(self): self._store = threading.local() def add(self, event): self.get_all().append(event) def clear(self): if self.has(): del self._store.events def get_all(self): if not self.has(): self._store.events = [] return self._store.events def has(self): return hasattr(self._store, 'events') def pop_event(self): return self._store.events.pop() if self.has() and self._store.events else None
åæ§ã«ã scoped_sessionã¯SQLAlchemyã«å®è£ ãããŠããŸããããã«ãããåã¹ã¬ããã®ããŒã¿ããŒã¹ã«äžæã®æ¥ç¶ã確ç«ã§ããŸãã
2çªç®ã®ã¢ãããŒãã䜿çšããå Žåãåãªã¯ãšã¹ãã®æåŸã«ã³ã³ãããç Žæ£ããæ°ãããªã¯ãšã¹ããåŠçããåã«æ°ããã³ã³ãããäœæããããšã«ãããã¡ã¢ãªã®åé¡ãåé¿ã§ããŸãã ããã¯ãPHPãªã¯ãšã¹ãåŠçã¢ãã«ã«éåžžã«äŒŒãŠããŸãã ãã€ãã¹-æ°ãããªã¯ãšã¹ãããšã«ã³ã³ãããšãµãŒãã¹ãåæåãããŸãïŒåãã³ãŒããåžžã«å®è¡ãããŸãïŒã Pythonã¹ã¬ãããå©çšããªãã
ãããã«
ç°ãªãèšèª-ç°ãªãã¢ãããŒãã Pythonã«ã¯ç¬èªã®ç¹æ§ããããããããæ£ãã䜿çšããæ¹æ³ã¯ãŸã æ確ã§ã¯ãããŸããã Pythonã¯ãã¢ããªã±ãŒã·ã§ã³ã®ç¶æ ãšãã«ãã¹ã¬ããã®ãªã¯ãšã¹ãåŠçãè¡ãæ©èœãæäŸããŸãããæœåšçãªå¯èœæ§ã®ãã競åç¶æ ïŒn + = 1ã§ãã¢ãããã¯æäœã§ã¯ãªããšããäºå®ã«ç §ãããŠïŒããã³ããããããè€éãªã¢ããªã±ãŒã·ã§ã³ã¢ãŒããã¯ãã£ã§æ¯æãå¿ èŠããããŸãã Pythonéçºè ãã²ããçãããWebã¢ããªã±ãŒã·ã§ã³ãã©ã®ããã«æ§ç¯ããŠãããèããŠã¿ããã