jeanphix / Ghost.py

Webkit based scriptable web browser for python.
http://ghost-py.readthedocs.org/en/latest/
2.76k stars 380 forks source link

Thread error when run in django view / mod_wsgi #17

Open danielstockton opened 12 years ago

danielstockton commented 12 years ago
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QApplication(0xba5dcf10), parent's thread is QThread(0xba4ece58), current thread is QThread(0xbaa1e188)

(<unknown>:23802): GLib-CRITICAL **: g_main_context_pop_thread_default: assertion `stack != NULL' failed
[Fri Jun 29 10:38:48 2012] [notice] child pid 23802 exit signal Segmentation fault (11)

The following code in the view is enough to cause the problem:

g = Ghost()
g.open('http://google.com')
html = g.content
g.exit()

It seems to exit more cleanly with the following change, at least I no longer receive any errors:

https://github.com/danielstockton/Ghost.py/blob/master/ghost/ghost.py#L330

jeanphix commented 12 years ago

I'll have a look at that later today.

danielstockton commented 12 years ago

My change is not the solution. I still receive the error, albeit less frequently.

A better solution, for me at least, is just to instantiate a singleton Ghost object when my application starts up and use that throughout.

jmg commented 11 years ago

What's the status on this issue? I've the same problem

jmg commented 11 years ago

In my case was solved by opening a new subprocess, creating the Ghost instance there and then exiting it when finished.

dolfandringa commented 11 years ago

I have this same problem in a WSGI application. I am getting this error: QObject: Cannot create children for a parent that is in a different thread. (Parent is QNetworkAccessManager(0x7f8114c62380), parent's thread is QThread(0x7f81142c2090), current thread is QThread(0x7f81200c5d30)

A quick google showed me this post http://stackoverflow.com/a/3268185/867162, which seems to concern the same problem, which involves multi threading. But how to solve problem, I don't know.

dolfandringa commented 11 years ago

I have been digging into the problem and am a bit wiser. The QNetworkAccessManager (in self.manager in Ghost) is the culprit. It seems QNetworkAccessManager is only started once, when Ghost is instantiated, even when you instantiate Ghost again, the same QNetworkAccessManager is used. So if you have a multithreaded application which instantiates Ghost() each time, the QNetworkAccessManager seems to be shared between these threads, which it doesn't like. But also if you start Ghost() only once, and each thread calls it's open() method, still you run into problems because the open() call can be run from different threads than the thread where Ghost() was instantiated, causing access to self.manager from the wrong thread again. So the point where you call Ghost() and Ghost.open() does not seem to make any difference.

dolfandringa commented 11 years ago

Ok, I now have a solution. By launching Ghost in a separate process, using multiprocessing, and thus effectively bypassing the GIL, you avoid the threading issues, since Ghost, QNetworkAccessManager and everything else Ghost/QT related is started in (one and the same) separate process.

This is what I did:

def createScreenshot(url,filename,features,layername):
    ghost=Ghost(viewport_size=(900,900),log_level=logging.DEBUG)
    ghost.open(url,method='post',body=urllib.urlencode({'features':features,'layername':layername}))
    ghost.capture_to(filename,region=(0,0,800,800))

class SomeClass(object):
    def some_method(self):
        .......
        proc=multiprocessing.Process(target=createScreenshot,args=(url,filename,features,layername))
        proc.start()
        proc.join()
tbluejeans commented 11 years ago

I am having the same issue, however the solution with multiprocessing does not work, I receive the following error when using multiprocessing:

QWaitCondition: Destroyed while threads are still waiting