Path: csiph.com!usenet.pasdenom.info!dedibox.gegeweb.org!gegeweb.eu!nntpfeed.proxad.net!proxad.net!feeder1-2.proxad.net!news.tele.dk!news.tele.dk!small.news.tele.dk!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.003 X-Spam-Evidence: '*H*': 0.99; '*S*': 0.00; 'python.': 0.02; 'python,': 0.02; 'else:': 0.03; 'yet.': 0.04; 'arrays': 0.09; 'calls.': 0.09; 'lines:': 0.09; 'measure': 0.09; 'slow.': 0.09; 'url:github': 0.09; 'cc:addr:python-list': 0.11; 'times,': 0.14; "(it's": 0.16; 'change;': 0.16; 'enough.': 0.16; 'from:addr:rosuav': 0.16; 'from:name:chris angelico': 0.16; 'iteration': 0.16; 'once.': 0.16; 'spots': 0.16; 'tweak': 0.16; 'language': 0.16; 'wrote:': 0.18; '(not': 0.18; 'drawing': 0.19; 'typing': 0.19; 'code,': 0.22; 'example': 0.22; 'rules': 0.22; 'cc:addr:python.org': 0.22; 'visible': 0.24; 'looks': 0.24; 'cc:2**0': 0.24; 'sort': 0.25; 'long,': 0.26; 'this:': 0.26; '(for': 0.26; 'gets': 0.27; 'header :In-Reply-To:1': 0.27; 'dec': 0.30; 'important.': 0.30; 'sets': 0.30; 'message-id:@mail.gmail.com': 0.30; 'code': 0.31; 'lines': 0.31; '(possibly': 0.31; 'are.': 0.31; 'subject:some': 0.31; 'probably': 0.32; 'up.': 0.33; 'running': 0.33; 'fri,': 0.33; 'guess': 0.33; 'actual': 0.34; 'noticed': 0.34; 'core': 0.34; 'skip:d 20': 0.34; "i'd": 0.34; 'could': 0.34; 'problem': 0.35; 'something': 0.35; 'but': 0.35; 'received:google.com': 0.35; 'tight': 0.36; "didn't": 0.36; 'should': 0.36; 'seconds': 0.37; 'application': 0.37; 'so,': 0.37; 'too': 0.37; 'two': 0.37; 'being': 0.38; 'pm,': 0.38; 'little': 0.38; 'does': 0.39; 'realize': 0.39; 'called': 0.40; 'how': 0.40; 'even': 0.60; 'commands': 0.60; 'experts': 0.60; 'profile': 0.61; "you're": 0.61; 'first': 0.61; "you'll": 0.62; 'real': 0.63; 'taking': 0.65; 'great': 0.65; 'cut': 0.74; 'million': 0.74; 'action.': 0.84; 'actually,': 0.84; 'amazed': 0.84; 'impact.': 0.84; 'stronger.': 0.84; 'to:none': 0.92; 'hot': 0.96; '2013': 0.98 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:cc :content-type; bh=6FSno0XIYsVIo2vb+18PwVm39LG5rs4UsLPHgNrOq2w=; b=L3SylrZAWEMtZ/KrqJqq80Y7YFpdE15DfPTIRwz6C7M2lOszjvvYfdYhefO4N0Dm55 VAXCBfYRvIh90U+vqBHnjy2C0QtxRl+JOuQJc0nU+hCAzFAiQrepiq1/6F8ZDdGOnMRD uU7Z/4FfQq0ZXGWyqY8SHdH2/R26xbiRLzLXdWeHch4uCACG/hzHaeJSY2VD3YJLpEa7 LcihHX3Z8Zd+qGI9BKFfyAqe3O4NjgBDwk0MxgmgvwqA5T395JRoeFF8gGK5oZteLudD dyu7pYCwKyDpi3xDcr+VdWvto/bWr8hdLLRUCbQeXHm95PJ1ZKCieKshDEi4RF3f5AHl xKrA== MIME-Version: 1.0 X-Received: by 10.66.102.39 with SMTP id fl7mr3724990pab.43.1386332014174; Fri, 06 Dec 2013 04:13:34 -0800 (PST) In-Reply-To: References: Date: Fri, 6 Dec 2013 23:13:34 +1100 Subject: Re: squeeze out some performance From: Chris Angelico Cc: "python-list@python.org" Content-Type: text/plain; charset=UTF-8 X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 57 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1386332017 news.xs4all.nl 2960 [2001:888:2000:d::a6]:58315 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:61137 On Fri, Dec 6, 2013 at 8:46 PM, Jeremy Sanders wrote: > This sort of code is probably harder to make faster in pure python. You > could try profiling it to see where the hot spots are. Perhaps the choice of > arrays or sets might have some speed impact. I'd make this recommendation MUCH stronger. Rule 1 of optimization: Don't. Rule 2 (for experts only): Don't yet. Once you find that your program actually is running too slowly, then AND ONLY THEN do you start looking at tightening something up. You'll be amazed how little you need to change; start with good clean idiomatic code, and then if it takes too long, you tweak just a couple of things and it's fast enough. And when you do come to the tweaking... Rule 3: Measure twice, cut once. Rule 4: Actually, measure twenty times, cut once. Profile your code to find out what's actually slow. This is very important. Here's an example from a real application (not in Python, it's in a semantically-similar language called Pike): https://github.com/Rosuav/Gypsum/blob/d9907e1507c52189c83ae25f5d7be85235b616fa/window.pike I noticed that I could saturate one CPU core by typing commands very quickly. Okay. That gets us past the first two rules (it's a MUD client, it should not be able to saturate one core of an i5). The code looks roughly like this: paint(): for line in lines: if line_is_visible: paint_line(line) paint_line(): for piece_of_text in text: if highlighted: draw_highlighted() else: draw_not_highlighted() My first guess was that the actual drawing was taking the time, since that's a whole lot of GTK calls. But no; the actual problem was the iteration across all lines and then finding out if they're visible or not (possibly because it obliterates the CPU caches). Once the scrollback got to a million lines or so, that was prohibitively expensive. I didn't realize that until I actually profiled the code and _measured_ where the time was being spent. How fast does your code run? How fast do you need it to run? Lots of optimization questions are answered by "Yaknow what, it don't even matter", unless you're running in a tight loop, or on a microcontroller, or something. Halving the time taken sounds great until you see that it's currently taking 0.0001 seconds and happens in response to user action. ChrisA