.pixels is a python object and pretty slow, especially if you change pixels. That is 'cause the entire buffer / python object is re-created for every single change (if you do it in a python loop). Not sure why it's that slow on read-only actions though...
You can speed it up tremendously if you cast it to a native python type (tuple) and use that copy instead:
img = bpy.data.images['Untitled']
pixels = img.pixels[:] # create a copy (tuple) for read-only access
# -- OR --
pixels = list(img.pixels) # create an editable copy (list)
# Use the tuple object, which is way faster than direct access to Image.pixels
for i in range(0, len(pixels), 4):
pixels[i] = 1.0 - pixels[i] # invert red channel
# Write back to image.
# Slice notation here means to replace in-place, not sure if it's faster...
img.pixels[:] = pixels
# Should probably update image