I took the shipping code that I ran in Flask (without Apache) and adapted it to run under Apache as a Flask app. That way, I'm comparing apples to apples. I'm comparing the performance of the shipping code between Flask and web2py.
Below, I've included the 'default' file from Apache2/sites-available for Flask. Basically, the code in Flask executes 10x faster than the same code in web2py. So my question is: if Apache is at fault for the web2py app's slow performance, why doesn't Apache hurt the Flask app's performance? (This doesn't seem to be related to GIL or WSGI.) <VirtualHost *:80> ServerName 10.211.55.7 WSGIDaemonProcess hello user=www-data group=www-data threads=5 WSGIScriptAlias / /home/richard/welcome/hello.wsgi <Directory /home/richard/welcome> Order Allow,Deny Allow from all </Directory> </VirtualHost> -- Resources: - http://web2py.com - http://web2py.com/book (Documentation) - http://github.com/web2py/web2py (Source code) - https://code.google.com/p/web2py/issues/list (Report Issues) --- You received this message because you are subscribed to the Google Groups "web2py-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to web2py+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
430x300x200 430x300x200 400x370x330 390x285x140 585x285x200 430x300x200 400x370x330 553x261x152 290x210x160 390x285x140
debug.out
Description: Binary data
from flask import Flask app = Flask(__name__) import time import sys import os debug_path = '/home/richard/welcome/debug.out' def debug(str): f = open(debug_path,'a') f.write(str+'\n') f.close() return # # pyShipping 1.8a # import time import random from shippackage import Package def packstrip(bin, p): """Creates a Strip which fits into bin. Returns the Packages to be used in the strip, the dimensions of the strip as a 3-tuple and a list of "left over" packages. """ # This code is somewhat optimized and somewhat unreadable s = [] # strip r = [] # rest ss = sw = sl = 0 # stripsize bs = bin.heigth # binsize sapp = s.append # speedup rapp = r.append # speedup ppop = p.pop # speedup while p and (ss <= bs): n = ppop(0) nh, nw, nl = n.size if ss + nh <= bs: ss += nh sapp(n) if nw > sw: sw = nw if nl > sl: sl = nl else: rapp(n) return s, (ss, sw, sl), r + p def packlayer(bin, packages): strips = [] layersize = 0 layerx = 0 layery = 0 binsize = bin.width while packages: strip, (sizex, stripsize, sizez), rest = packstrip(bin, packages) if layersize + stripsize <= binsize: if not strip: # we were not able to pack anything break layersize += stripsize layerx = max([sizex, layerx]) layery = max([sizez, layery]) strips.extend(strip) packages = rest else: # Next Layer please packages = strip + rest break return strips, (layerx, layersize, layery), packages def packbin(bin, packages): packages.sort() layers = [] contentheigth = 0 contentx = 0 contenty = 0 binsize = bin.length while packages: layer, (sizex, sizey, layersize), rest = packlayer(bin, packages) if contentheigth + layersize <= binsize: if not layer: # we were not able to pack anything break contentheigth += layersize contentx = max([contentx, sizex]) contenty = max([contenty, sizey]) layers.extend(layer) packages = rest else: # Next Bin please packages = layer + rest break return layers, (contentx, contenty, contentheigth), packages def packit(bin, originalpackages): packedbins = [] packages = sorted(originalpackages) while packages: packagesinbin, (binx, biny, binz), rest = packbin(bin, packages) if not packagesinbin: # we were not able to pack anything break packedbins.append(packagesinbin) packages = rest # we now have a result, try to get a better result by rotating some bins return packedbins, rest # In newer Python versions these van be imported: # from itertools import permutations def product(*args, **kwds): # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111 pools = map(tuple, args) * kwds.get('repeat', 1) result = [[]] for pool in pools: result = [x + [y] for x in result for y in pool] for prod in result: yield tuple(prod) def permutations(iterable, r=None): pool = tuple(iterable) n = len(pool) r = n if r is None else r for indices in product(range(n), repeat=r): if len(set(indices)) == r: yield tuple(pool[i] for i in indices) class Timeout(Exception): pass def allpermutations_helper(permuted, todo, maxcounter, callback, bin, bestpack, counter): if not todo: return counter + callback(bin, permuted, bestpack) else: others = todo[1:] thispackage = todo[0] for dimensions in set(permutations((thispackage[0], thispackage[1], thispackage[2]))): thispackage = Package(dimensions, nosort=True) if thispackage in bin: counter = allpermutations_helper(permuted + [thispackage], others, maxcounter, callback, bin, bestpack, counter) if counter > maxcounter: raise Timeout('more than %d iterations tries' % counter) return counter def trypack(bin, packages, bestpack): bins, rest = packit(bin, packages) if len(bins) < bestpack['bincount']: bestpack['bincount'] = len(bins) bestpack['bins'] = bins bestpack['rest'] = rest if bestpack['bincount'] < 2: raise Timeout('optimal solution found') return len(packages) def allpermutations(todo, bin, iterlimit=5000): random.seed(1) random.shuffle(todo) bestpack = dict(bincount=len(todo) + 1) start = time.time() try: # First try unpermuted trypack(bin, todo, bestpack) # now try permutations allpermutations_helper([], todo, iterlimit, trypack, bin, bestpack, 0) except Timeout: pass debug('Elapsed time: '+str(time.time() - start)) return bestpack['bins'], bestpack['rest'] def binpack(packages, bin=None, iterlimit=5000): """Packs a list of Package() objects into a number of equal-sized bins. Returns a list of bins listing the packages within the bins and a list of packages which can't be packed because they are to big.""" if not bin: bin = Package("600x400x400") return allpermutations(packages, bin, iterlimit) def test(): test_path = '/home/richard/welcome/testdata.txt' fd = open(test_path) vorher = 0 nachher = 0 debug('Begin...') for line in fd: packages = [Package(pack) for pack in line.strip().split()] if not packages: continue bins, rest = binpack(packages) if rest: debug("invalid data") else: vorher += len(packages) nachher += len(bins) debug('Percentage fill: '+str(float(nachher) / vorher * 100)) return @app.route("/") def hello(): test() return "Hello World!" if __name__ == "__main__": app.run(host='0.0.0.0')
hello.wsgi
Description: Binary data
# encoding: utf-8 """ package.py - shipping/cargo related calculations based on a unit of shipping (box, crate, package) Created by Maximillian Dornseif on 2006-12-02. Copyright HUDORA GmbH 2006, 2007, 2010 You might consider this BSD-Licensed. """ import doctest import unittest import os debug_path = '/home/www-data/web2py/applications/HorridoHobbies/static/debug.out' def debug(str): f = open(debug_path,'a') f.write(str+'\n') f.close() return class Package(object): """Represents a package as used in cargo/shipping aplications.""" def __init__(self, size, weight=0, nosort=False): """Generates a new Package object. The size can be given as an list of integers or an string where the sizes are determined by the letter 'x': >>> Package((300, 400, 500)) <Package 500x400x300> >>> Package('300x400x500') <Package 500x400x300> """ #debug("RKE:initialize Package") self.weight = weight if "x" in size: self.heigth, self.width, self.length = [int(x) for x in size.split('x')] else: self.heigth, self.width, self.length = size #debug("RKE: "+str(self.heigth)+" "+str(self.width)+" "+str(self.length)) if not nosort: (self.heigth, self.width, self.length) = sorted((int(self.heigth), int(self.width), int(self.length)), reverse=True) self.volume = self.heigth * self.width * self.length self.size = (self.heigth, self.width, self.length) def _get_gurtmass(self): """'gurtamss' is the circumference of the box plus the length - which is often used to calculate shipping costs. >>> Package((100,110,120)).gurtmass 540 """ dimensions = (self.heigth, self.width, self.length) maxdimension = max(dimensions) otherdimensions = list(dimensions) del otherdimensions[otherdimensions.index(maxdimension)] return maxdimension + 2 * (sum(otherdimensions)) gurtmass = property(_get_gurtmass) def hat_gleiche_seiten(self, other): """Pr?ft, ob other mindestens eine gleich grosse Seite mit self hat.""" meineseiten = set([(self.heigth, self.width), (self.heigth, self.length), (self.width, self.length)]) otherseiten = set([(other.heigth, other.width), (other.heigth, other.length), (other.width, other.length)]) return bool(meineseiten.intersection(otherseiten)) def __getitem__(self, key): """The coordinates can be accessed as if the object is a tuple. >>> p = Package((500, 400, 300)) >>> p[0] 500 """ if key == 0: return self.heigth if key == 1: return self.width if key == 2: return self.length if isinstance(key, tuple): return (self.heigth, self.width, self.length)[key[0]:key[1]] if isinstance(key, slice): return (self.heigth, self.width, self.length)[key] raise IndexError def __contains__(self, other): """Checks if on package fits within an other. >>> Package((1600, 250, 480)) in Package((1600, 250, 480)) True >>> Package((1600, 252, 480)) in Package((1600, 250, 480)) False """ return self[0] >= other[0] and self[1] >= other[1] and self[2] >= other[2] def __hash__(self): return self.heigth + (self.width << 16) + (self.length << 32) def __eq__(self, other): """Package objects are equal if they have exactly the same dimensions. Permutations of the dimensions are considered equal: >>> Package((100,110,120)) == Package((100,110,120)) True >>> Package((120,110,100)) == Package((100,110,120)) True """ return (self.heigth == other.heigth and self.width == other.width and self.length == other.length) def __cmp__(self, other): """Enables to sort by Volume.""" return cmp(self.volume, other.volume) def __mul__(self, multiplicand): """Package can be multiplied with an integer. This results in the Package beeing stacked along the biggest side. >>> Package((400,300,600)) * 2 <Package 600x600x400> """ return Package((self.heigth, self.width, self.length * multiplicand), self.weight * multiplicand) def __add__(self, other): """ >>> Package((1600, 250, 480)) + Package((1600, 470, 480)) <Package 1600x720x480> >>> Package((1600, 250, 480)) + Package((1600, 480, 480)) <Package 1600x730x480> >>> Package((1600, 250, 480)) + Package((1600, 490, 480)) <Package 1600x740x480> """ meineseiten = set([(self.heigth, self.width), (self.heigth, self.length), (self.width, self.length)]) otherseiten = set([(other.heigth, other.width), (other.heigth, other.length), (other.width, other.length)]) if not meineseiten.intersection(otherseiten): raise ValueError("%s has no fitting sites to %s" % (self, other)) candidates = sorted(meineseiten.intersection(otherseiten), reverse=True) stack_on = candidates[0] mysides = [self.heigth, self.width, self.length] mysides.remove(stack_on[0]) mysides.remove(stack_on[1]) othersides = [other.heigth, other.width, other.length] othersides.remove(stack_on[0]) othersides.remove(stack_on[1]) return Package((stack_on[0], stack_on[1], mysides[0] + othersides[0]), self.weight + other.weight) def __str__(self): if self.weight: return "%dx%dx%d %dg" % (self.heigth, self.width, self.length, self.weight) else: return "%dx%dx%d" % (self.heigth, self.width, self.length) def __repr__(self): if self.weight: return "<Package %dx%dx%d %d>" % (self.heigth, self.width, self.length, self.weight) else: return "<Package %dx%dx%d>" % (self.heigth, self.width, self.length) def buendelung(kartons, maxweight=31000, maxgurtmass=3000): """Versucht Pakete so zu b?ndeln, so dass das Gurtmass nicht ?berschritten wird. Gibt die geb?ndelten Pakete und die nicht b?ndelbaren Pakete zur?ck. >>> buendelung([Package((800, 310, 250)), Package((800, 310, 250)), Package((800, 310, 250)), Package((800, 310, 250))]) (1, [<Package 800x750x310>], [<Package 800x310x250>]) >>> buendelung([Package((800, 310, 250)), Package((800, 310, 250)), Package((800, 310, 250)), Package((800, 310, 250)), Package((450, 290, 250)), Package((450, 290, 250))]) (2, [<Package 800x750x310>, <Package 500x450x290>], [<Package 800x310x250>]) """ MAXKARTOONSIMBUENDEL = 6 if not kartons: return 0, [], kartons gebuendelt = [] rest = [] lastkarton = kartons.pop(0) buendel = False buendelcounter = 0 kartons_im_buendel = 1 while kartons: currentcarton = kartons.pop(0) # check if 2 dimensions fit if (currentcarton.hat_gleiche_seiten(lastkarton) and (lastkarton.weight + currentcarton.weight < maxweight) and ((lastkarton + currentcarton).gurtmass < maxgurtmass) and (kartons_im_buendel < MAXKARTOONSIMBUENDEL)): # new carton has the same size in two dimensions and the sum of both in the third # ok, we can bundle lastkarton = (lastkarton + currentcarton) kartons_im_buendel += 1 if buendel is False: # neues B?ndel buendelcounter += 1 buendel = True else: # different sizes, or too big if buendel: gebuendelt.append(lastkarton) else: rest.append(lastkarton) kartons_im_buendel = 1 lastkarton = currentcarton buendel = False if buendel: gebuendelt.append(lastkarton) else: rest.append(lastkarton) return buendelcounter, gebuendelt, rest def pack_in_bins(kartons, versandkarton): """Implements Bin-Packing. You provide it with a bin size and a list of Package Objects to be bined. Returns a list of lists representing the bins with the binned Packages and a list of Packages too big for binning. >>> pack_in_bins([Package('135x200x250'), Package('170x380x390'), Package('485x280x590'), Package('254x171x368'), Package('201x172x349'), Package('254x171x368')], \ Package('600x400x400')) ([[<Package 250x200x135>, <Package 349x201x172>, <Package 368x254x171>], [<Package 368x254x171>, <Package 390x380x170>]], [<Package 590x485x280>]) """ import pyshipping.binpack toobig, packagelist, bins, rest = [], [], [], [] for box in sorted(kartons, reverse=True): if box not in versandkarton: # passt eh nicht toobig.append(box) else: packagelist.append(box) if packagelist: bins, rest = pyshipping.binpack.binpack(packagelist, versandkarton) return bins, toobig + rest ### Tests class PackageTests(unittest.TestCase): """Simple tests for Package objects.""" def test_init(self): """Tests object initialisation with different constructors.""" self.assertEqual(Package((100, 100, 200)), Package(('100', '200', '100'))) self.assertEqual(Package((100.0, 200.0, 200.0)), Package('200x200x100')) def test_eq(self): """Tests __eq__() implementation.""" self.assertEqual(Package((200, 100, 200)), Package(('200', '100', '200'))) self.assertNotEqual(Package((200, 200, 100)), Package(('100', '100', '200'))) def test_volume(self): """Tests volume calculation""" self.assertEqual(4000000, Package((100, 200, 200)).volume) self.assertEqual(8000, Package((20, 20, 20)).volume) def test_str(self): """Test __unicode__ implementation.""" self.assertEqual('200x200x100', Package((100, 200, 200)).__str__()) self.assertEqual('200x200x100', Package('100x200x200').__str__()) def test_repr(self): """Test __repr__ implementation.""" self.assertEqual('<Package 200x200x100 44>', Package((100, 200, 200), 44).__repr__()) def test_gurtmass(self): """Test gurtmass calculation.""" self.assertEqual(800, Package((100, 200, 200)).gurtmass) self.assertEqual(900, Package((100, 200, 300)).gurtmass) self.assertEqual(1000, Package((200, 200, 200)).gurtmass) self.assertEqual(3060, Package((1600, 250, 480)).gurtmass) def test_mul(self): """Test multiplication.""" self.assertEqual(Package((200, 200, 200)), Package((100, 200, 200)) * 2) def test_sort(self): """Test multiplication.""" data = [Package((1600, 490, 480)), Package((1600, 470, 480)), Package((1600, 480, 480))] data.sort() self.assertEqual(data, [Package((1600, 470, 480)), Package((1600, 480, 480)), Package((1600, 490, 480))]) if __name__ == '__main__': factor = 0 while True: factor += 1 single = Package((750, 240, 220), 7400) multi = single * factor if multi.weight > 31000 or multi.gurtmass > 3000: multi = single * (factor - 1) #print factor - 1, multi, multi.gurtmass break doctest.testmod() unittest.main()