Posts tagged ‘cpu’

Python - Not Quite Perfect … But Darn Good

For the last few years I’ve been working heavily in the Python programming language. It’s an absolutely wonderful language and I do love it so. Besides forcing good indentation practices and being otherwise good with whitespace, it also is a wonderfully clever little language with many neat tricks that a seasoned programmer can appreciate.

However, it’s not all sunshine and lollipops.

For being an interpreted language, most of it runs quite fast. And where its speed does fail, there’s always writing libraries in C++ and then wrapping it in Python to use in your Python code. So most of the time it has a wonderful performance if you know what you’re doing.

Just recently though, while working on some string code to remove ASCII characters 128-255 from strings, as these beyond-standard-ASCII characters don’t translate to Unicode, I am reminded of one of Pythons massive failings. It handles strings for sh_t.

Don’t get me wrong. Python has all sorts of neat methods and functions for string manipulation. It’s quite handy really. But it’s s…l…o…w. Something about the way that Python assigns a new string variable is just darn slow. And nearly every string operation requires you to assign a new string variable as each function / method returns a string that is your results. So when all of your functions return a new string, and creating new strings in Python is slow … you see how this is a very bad combination.

For example, the code I was working on. A really neat Pythonic way of doing things results in the function:

def stripBadASCII1(contents):
    if not contents: return contents
    return “”.join([c for c in contents if ord(c) < 128])

This strange looking code goes through contents character by character and only joins the characters below ASCII 128 to the returned string. Simple. Neat. Effective. But keep in mind, the way Python works, for each new character joined to the string, it has to create a whole new string. And in Python this is molasses in January slow.

Now another method, a little more mundane in concept, goes like this:

def stripBadASCII2(contents):
    if not contents: return contents
    for i in range(128,256):
        contents = contents.replace(chr(i), “”)
    return contents

You see, the concept of this one is easier to follow. It replaces all bad ASCII characters in the string with an empty string, which effectively strips those characters from the string. Looping 128 times through the string for each bad ASCII character. Ugly. Messy. And yet, because it moves string contents in chunks instead of character by character, the number of new string operations is greatly reduced. So even though it loops 128 times through, where as the other function only executes once, it still manages to run faster for all of its seemingly slow 128 loops.

When I ran function 1, the character by character approach, through the contents of a test file typically used in the code this function is being written for, on average it took about 0.1 seconds.

When I ran function 2 through the same contents, using the seemingly slower 128 loop approach, it took on average 0.06 seconds.

Okay, so four hundredths of a second doesn’t seem like much of a difference. But the longer the string processed through these functions, the larger that difference will get. And more to the point, this my friends is how bad Python is at handling strings. A single pass through, character by character, is almost twice as slow as 128 loops through with chunks of characters processed together. Ouch. This certainly isn’t the C++ approach to strings.

So that’s one of Python’s major failings, is it’s string handling performance. Python has another major performance failing as well. Even though it can create and manage threads, it doesn’t ever use more than one processor. So if you have a multi-core CPU, you only use one core. If you have a multi-processor PC, it only uses one processor. If you have a dual CPU quadcore PC with a total of eight cores, it still runs on just one core of one processor. No matter how many threads your Python code contains. Ouch!

In fact, because of the overhead of thread management, and because it only runs on one CPU, Python actually runs slower the more threads you give it to handle. Yikes!

In the old days when multi-CPU computers were rare and multiple cores per CPU was unheard of, this was not a problem. Today is not those old days. Today two, three, and four core CPUs are common for desktops. Heck, I just built my hun’s new budget computer with a dualcore Celeron. So more than anything, this is really an issue Python needs to fix, and soon. They’ve put this one off far too long already.

A workaround is to try and develop your code as multi-process not multi-threaded. Or in other words break the program down into independent sub-programs that the main program can spawn as needed. There are memory sharing techniques that can be used for inter-process communication. It’s ugly. It’s messy. But being independent Python processes, they should spread across multiple CPUs/cores like a normal multi-threaded program would. Still, it’s very far from an ideal solution. It is just another messy workaround.

So that, my friends, is the down side of Python. It’s a wonderful language, but no language is perfect. They each have their own strengths and weaknesses, and Python is no exception.

Dualcore - Do You Get It? Do You NEED It?

A picture of the insides of a dualcore Opteron CPU.

They’re as common as chips today. Dualcore CPUs are everywhere you look. They’re almost the standard now, and quadcore (or higher) are the much ballyhooed upper end. But do you really know what a dualcore processor even is? More importantly, do you actually know what having one means? Here’s a little help for the common (and perhaps not so common) woman and man.

At its heart, a dualcore processor is simple. Take two computer processors. Squish them together. Give them one socket to plug in to so that seems like they’re one processor. Now you have a dualcore CPU. It’s literally two computer processors in one. How these two processors talk to each other (and everything else in your computer) varies widely. For the most part it makes little difference. Oh sure, geeks can argue the finer details of this until they’re blue in the face, but when it comes down to the performance that you and I see, the technical details matter very little. In high-use servers they matter. In desktop and laptop computers, they don’t.

Now, you might be thinking this is great. Two processors in one, that’s like double the processing power. So everything should run twice as fast. Well, sorry, but wrong.

Yes you have a theoretical doubling of performance. There is twice as much of everything there. But that double is still split in two. And more often than not, a single task cannot be split into two for both cores in your dualcore to work on simultaneously.

At the risk of getting into too much technical detail, I’ll break down why. There are two ways to write a computer program. The first is called single-threaded. (A thread is like a strand of code.) Single-threaded programs are easy to write. They were the first kind. All logic flows in a simple easy to understand manner. You calculate A. You perform A. You calculate B. You perform B. It’s all very straight forward. The behavior is very easy to understand and predict. And the only flaw to this method is that because the logic only runs through a single thread, only one core at a time can run this kind of program. In a dualcore CPU the other core will sit there and twiddle its thumbs.

The other way to write a computer program is called multi-threaded. The program is in effect broken down into smaller part-programs, called threads. These threads are then woven together by a lot of code to synchronize and control them. Because the program is broken down into parts this allows each core to grab at least one part of the program for itself, so no core sits idle. The gain is that in computers with multiple processors or a processor with multiple cores the program, as broken into threads, can run parts on each processor and/or core, effectively using a lot more of the resources available. The downside however is many fold. On a single core processor where there are no additional resources to be gained, the overhead of timing, control, communication, and synchronization of the threaded parts causes a loss in performance. Also all of this overhead creates many new places in the program for things to go wrong or even break, meaning a lot more bugs are likely to be in the program. But on top of that all, the job of the programmer to sort non-linearly through this multi-threaded code to find and fix bugs becomes exponentially more challenging than stepping through linear single-threaded code. So this all adds to a vast increase in development time and cost of a program, as well as greatly increasing the likelihood that it will be sold with unfixed flaws.

But that still isn’t all. On top of it all is the simple fact that not all computer programs lend themselves well to being broken into smaller pieces. Some programs do. Programs that repeatedly perform the same tasks over and over for example, can run several instances of those same tasks simultaneously in a multi-threaded program to fully utilize a dualcore processor. And programs that perform a vast multitude of very simple calculations that do not depend upon each other, such as the artificial intelligences that run opponents in a game, can also be split well into a multi-threaded program that will well use a dualcore CPU. However, many programs don’t perform tasks that can be broken up. One answer always depends on the previous, and so forth, so that the mathematics cannot be split up. While other programs (like word processors, email, web browsers, et cetera) simply don’t do much and are always just sitting there idle, waiting for user input. So they have nothing to gain from multi-threading.

And finally, one thing that often happens is that when you get a dualcore processor, each core actually runs slower than a processor of equal value with just one core. And since most programs are single-threaded and thus can only use one core at a time, they will run slower on that slower-clocked dualcore than if you had that faster-clocked single core processor.

So in light of all of this, what does having a dualcore CPU actually give you?

Well, for starters, switching between programs should be much smoother. For people who multi-task it will make a notable improvement in the snappiness and responsiveness of switching back and forth between programs. It also allows multiple programs to better run at the same time. Since today we have so many programs running in the background (anti-virus, firewall, chat and IMs, email, audio player, and so forth) a dualcore processor allows you to run what you want to run unhindered by all of those little things. And, of course, there are some programs like image editing software and some games that can greatly take advantage of both cores of a dualcore processor.

So the next time you go to buy a new computer or upgrade your computer processor, take a real hard look at what you do on your computer. Are the programs you run going to need a lot of processing power? Are the programs you run multi-threaded? Are you a multi-tasker that runs a lot of programs simultaneously? The answers to these questions will help you better choose the computer processor that you need.