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 [email protected].
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()

