Skip to main content

Ralsina.Me — Roberto Alsina's website

Antisocial Networks

I love http://­goodread­s.­com very much. It has mea­sur­ably im­proved my life as a read­er. I have read au­thors I would­n't have read with­out it, books from those au­thors I would have ig­nored, and keeps track of what I read, am read­ing and will read.

What it has nev­er been for me, is a so­cial net­work. I would be about as hap­py with it if I knew noone else on the site, if it were just me and a bazil­lion strangers whose taste I can leech of­f.

Sure, I have a few friends there nowa­days, but I hard­ly ev­er do any­thing "so­cial" be­yond ac­cept­ing re­quests and post­ing re­views which I have no idea if some­one read­s.

I love Flickr where I put most of my pic­tures (soon: all of my pic­tures). It's cheap and I can up­load an al­most in­fi­nite amount of pics there, and I can share them with friends and fam­i­ly some­times (by re­post­ing them to face­book).

They were even kind enough to store the pic­tures I up­load­ed as a free us­er un­til I paid for the space to store them 5 years lat­er.

I love Twit­ter be­cause it's a place to post short things that don't de­serve a blog post, to chat­ter with friends and not-­so-friend­s, to know more peo­ple, and to waste some time ev­ery day.

One of those things is not like the oth­er­s. One of those things I use for its so­cial fea­tures, the oth­ers I use for oth­er rea­son­s, and I don't re­al­ly care about them be­ing so­cial or not.

I think nowa­days, for a so­cial net­work to suc­ceed, it has to cater to the an­ti­so­cial, at least at first, when you know noone there. I don't go to Flickr to de­bate. I don't go to Goodreads to chat. I go there to put pic­tures and keep my books straight. And that's what kept me there long enough to meet peo­ple.

The blogs I don't have

  • Things you on­­ly like or be­lieve be­­cause your mom said so.

  • Tips for Time Trav­el­er­s.

  • Cute plants and their an­tic­s.

  • 1001 ways to peal a cat.

  • Things mor­ti­­cians say.

  • Trav­el­ing for Time Tip­per­s.

  • Coins of the world: what do they taste like?

  • Things found in peo­­ple's noses.

  • Sur­prise, that is not chick­­en!

  • Time for Tip Trav­el­er­s.

  • World of Lin­t.

Kill the Dead (Sandman Slim, #2)

Cover for Kill the Dead (Sandman Slim, #2)

Review:

This is not a book. It's the sec­ond half of "Sand­man Slim". Read that and then de­cide if you ac­tu­al­ly want to read this sec­ond half or not.

Me, I liked it, thank you very much.

PyQt Quickie: Don't Get Garbage Collected

There is one area where Qt and Python (and in con­se­quence PyQt) have ma­jor dis­agree­ments. That area is mem­o­ry man­age­men­t.

While Qt has its own mech­a­nisms to han­dle ob­ject al­lo­ca­tion and dis­pos­al (the hi­er­ar­chi­cal QOb­ject trees, smart point­er­s, etc.), PyQt runs on Python, so it has garbage col­lec­tion.

Let's con­sid­er a sim­ple ex­am­ple:

from PyQt4 import QtCore

def finished():
    print "The process is done!"
    # Quit the app
    QtCore.QCoreApplication.instance().quit()

def launch_process():
    # Do something asynchronously
    proc = QtCore.QProcess()
    proc.start("/bin/sleep 3")
    # After it finishes, call finished
    proc.finished.connect(finished)

def main():
    app = QtCore.QCoreApplication([])
    # Launch the process
    launch_process()
    app.exec_()

main()

If you run this, this is what will hap­pen:

QProcess: Destroyed while process is still running.
The process is done!

Plus, the script never ends. Fun! The problem is that proc is being deleted at the end of launch_process because there are no more references to it.

Here is a bet­ter way to do it:

from PyQt4 import QtCore

processes = set([])

def finished():
    print "The process is done!"
    # Quit the app
    QtCore.QCoreApplication.instance().quit()

def launch_process():
    # Do something asynchronously
    proc = QtCore.QProcess()
    processes.add(proc)
    proc.start("/bin/sleep 3")
    # After it finishes, call finished
    proc.finished.connect(finished)

def main():
    app = QtCore.QCoreApplication([])
    # Launch the process
    launch_process()
    app.exec_()

main()

Here, we add a global processes set and add proc there so we always keep a reference to it. Now, the program works as intended. However, it still has an issue: we are leaking QProcess objects.

While in this case the leak is very short­-lived, since we are end­ing the pro­gram right af­ter the process end­s, in a re­al pro­gram this is not a good idea.

So, we would need to add a way to remove proc from processes in finished. This is not as easy as it may seem. Here is an idea that will not work as you expect:

def launch_process():
    # Do something asynchronously
    proc = QtCore.QProcess()
    processes.add(proc)
    proc.start("/bin/sleep 3")
    # Remove the process from the global set when done
    proc.finished.connect(lambda: processes.remove(proc))
    # After it finishes, call finished
    proc.finished.connect(finished)

In this version, we will still leak proc, even though processes is empty! Why? Because we are keeping a reference to proc in the lambda!

I don't really have a good answer for that that doesn't involve turning everything into members of a QObject and using sender to figure out what process is ending, or using QSignalMapper. That version is left as an exercise.


Contents © 2000-2024 Roberto Alsina