[ SEA-GHOST MINI SHELL]
#! /usr/bin/env python
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
# $Id: test_multi_vs_thread.py,v 1.16 2005/04/12 03:39:01 mfx Exp $
import os, sys, time
from threading import Thread, RLock
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
import pycurl
# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
# the libcurl tutorial for more info.
try:
import signal
from signal import SIGPIPE, SIG_IGN
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
except ImportError:
pass
# The conclusion is: the multi interface is fastest!
NUM_PAGES = 30
NUM_THREADS = 10
assert NUM_PAGES % NUM_THREADS == 0
##URL = "http://pycurl.sourceforge.net/tests/testgetvars.php?%d"
URL = "http://pycurl.sourceforge.net/tests/teststaticpage.html?%d"
#
# util
#
class Curl:
def __init__(self, url):
self.url = url
self.body = StringIO()
self.http_code = -1
# pycurl API calls
self._curl = pycurl.Curl()
self._curl.setopt(pycurl.URL, self.url)
self._curl.setopt(pycurl.WRITEFUNCTION, self.body.write)
self._curl.setopt(pycurl.NOSIGNAL, 1)
def perform(self):
self._curl.perform()
def close(self):
self.http_code = self._curl.getinfo(pycurl.HTTP_CODE)
self._curl.close()
def print_result(items):
return # DO NOTHING
#
for c in items:
data = c.body.getvalue()
if 0:
print "**********", c.url, "**********"
print data
elif 1:
print "%-60s %3d %6d" % (c.url, c.http_code, len(data))
###
### 1) multi
###
def test_multi():
clock1 = time.time()
# init
handles = []
m = pycurl.CurlMulti()
for i in range(NUM_PAGES):
c = Curl(URL %i)
m.add_handle(c._curl)
handles.append(c)
clock2 = time.time()
# stir state machine into action
while 1:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM:
break
# get data
while num_handles:
m.select(1.0)
while 1:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM:
break
clock3 = time.time()
# close handles
for c in handles:
c.close()
m.close()
clock4 = time.time()
print "multi interface: %d pages: perform %5.2f secs, total %5.2f secs" % (NUM_PAGES, clock3 - clock2, clock4 - clock1)
# print result
print_result(handles)
###
### 2) thread
###
class Test(Thread):
def __init__(self, lock=None):
Thread.__init__(self)
self.lock = lock
self.items = []
def run(self):
if self.lock:
self.lock.acquire()
self.lock.release()
for c in self.items:
c.perform()
def test_threads(lock=None):
clock1 = time.time()
# create and start threads, but block them
if lock:
lock.acquire()
# init (FIXME - this is ugly)
threads = []
handles = []
t = None
for i in range(NUM_PAGES):
if i % (NUM_PAGES / NUM_THREADS) == 0:
t = Test(lock)
if lock:
t.start()
threads.append(t)
c = Curl(URL % i)
t.items.append(c)
handles.append(c)
assert len(handles) == NUM_PAGES
assert len(threads) == NUM_THREADS
clock2 = time.time()
#
if lock:
# release lock to let the blocked threads run
lock.release()
else:
# start threads
for t in threads:
t.start()
# wait for threads to finish
for t in threads:
t.join()
clock3 = time.time()
# close handles
for c in handles:
c.close()
clock4 = time.time()
if lock:
print "thread interface [lock]: %d pages: perform %5.2f secs, total %5.2f secs" % (NUM_PAGES, clock3 - clock2, clock4 - clock1)
else:
print "thread interface: %d pages: perform %5.2f secs, total %5.2f secs" % (NUM_PAGES, clock3 - clock2, clock4 - clock1)
# print result
print_result(handles)
###
### 3) thread - threads grab curl objects on demand from a shared pool
###
class TestPool(Thread):
def __init__(self, lock, pool):
Thread.__init__(self)
self.lock = lock
self.pool = pool
def run(self):
while 1:
self.lock.acquire()
c = None
if self.pool:
c = self.pool.pop()
self.lock.release()
if c is None:
break
c.perform()
def test_thread_pool(lock):
clock1 = time.time()
# init
handles = []
for i in range(NUM_PAGES):
c = Curl(URL %i)
handles.append(c)
# create and start threads, but block them
lock.acquire()
threads = []
pool = handles[:] # shallow copy of the list, shared for pop()
for i in range(NUM_THREADS):
t = TestPool(lock, pool)
t.start()
threads.append(t)
assert len(pool) == NUM_PAGES
assert len(threads) == NUM_THREADS
clock2 = time.time()
# release lock to let the blocked threads run
lock.release()
# wait for threads to finish
for t in threads:
t.join()
clock3 = time.time()
# close handles
for c in handles:
c.close()
clock4 = time.time()
print "thread interface [pool]: %d pages: perform %5.2f secs, total %5.2f secs" % (NUM_PAGES, clock3 - clock2, clock4 - clock1)
# print result
print_result(handles)
lock = RLock()
if 1:
test_multi()
test_threads()
test_threads(lock)
test_thread_pool(lock)
else:
test_thread_pool(lock)
test_threads(lock)
test_threads()
test_multi()
SEA-GHOST - SHELL CODING BY SEA-GHOST