一次失败的QThread多线程加载Webpage.load()页面的尝试

原创 2016年07月19日 15:09:19

问题

前段时间在用PyQt4写网页加载部分时一开始用的从QWebView.load()(QWebFrame.load()),但由于这样会卡住GUI,于是换了QNetworkAccessManager模块来访问网络,返回内容用setcontent()传递给QWebView:

http://blog.csdn.net/chroming/article/details/51832244

当时还觉得解决了一个挺有意义的问题,毕竟搜索GUI卡住的问题确实有不少人因为load()导致GUI界面卡住。

由于QNetworkAccessManager是比较底层的访问网络模块,不少东西要自己处理。比如某些网址HTML中声明的编码与response header中声明的编码不同导致的网页显示乱码,某些网页无法显示等问题。对于乱码问题我还通过读取response header解决了一部分,但对于无法显示的问题却没找到原因。后来测试QWebFrame.load(),发现这些问题都不存在。于是考虑使用多线程加载网页,既能解决各种兼容性问题,又不会导致GUI卡住。

寻找解决办法

虽然Python自己有多线程模块,但因为程序里用了很多Qt模块,这里也考虑直接用Qt的自带多线程模块,QThread。搜了资料,写出了独立的多线程模块:

# -*- coding: utf-8 -*-
from PyQt4 import QtCore


# load加载页面线程
class loadUrl(QtCore.QThread):
    def __init__(self, qurl, qwebframe, parent=None):
        super(loadUrl, self).__init__(parent)
        self.qurl = qurl
        self.qwebframe = qwebframe

    def run(self):
        self.qwebframe.load(self.qurl)

在主代码中调用多线程模块:

class test():
    ...
    def testfun():
        ...
        from multiThread import loadUrl
        self.multiget = loadUrl(QUrl(input_url), self.webView.page().mainFrame())
        self.multiget.start()

结果出现了错误:

QObject: Cannot create children for a parent that is in a different thread

网上查到类似的情况:http://stackoverflow.com/questions/7143088/how-do-you-set-up-multiple-multithreaded-qwebviews-in-pyqt

回答如下:

There are multiple issues with your question and code:

  • You are talking about QWebFrame, but are actually passing a QWebView to your worker(s). Since this is a QWidget, it belongs to the main (GUI) thread and should not be modified by other threads.
  • One QWebView / QWebFrame can only load one URL at a time, so you cannot share it across multiple workers.
  • QWebFrame.load() loads data asynchronously, i.e. a call to load() returns immediately and there will be no data to read yet. You will have to wait for the loadFinished() signal to be emitted before you can access the data.
  • Since the actual loading is done by the networking layer of the operating system, and the *load()*method does not block, there is no need to run it in a separate thread in the first place. Why do you claim that this should be faster – it makes no sense.
  • Since you want to load hundreds of URLs in parallel (or about 10, you are mentioning both in the same sentence), are you sure that you want to use QWebFrame, which is a presentation class? Do you actually want to render the HTML or are you just interested in the data retrieved?

其中第一个issue回答了为什么会出现这个报错:主线程中的QWebFrame不能用子线程修改。但相比这条我更在意第三第四条:QWebFrame.load()是异步加载页面的,并不会阻塞主线程,不需要用子线程去加载页面。这就奇怪了,之前我用的时候明明是因为加载页面导致GUI卡住的。于是回去看自己的代码,发现了一点:

self.webView.load(QUrl(input_url))
app.restoreOverrideCursor()

于是随手把app.restoreOverrideCursor() 改到load之前。结果发现不卡了!一直以来困扰我的竟然是由于这个!

总结

这个问题让我花了一些冤枉时间来处理网页兼容性,结果发现只是一个小小的失误导致的。虽然之前在搜索网页卡住的问题时也看到有人说load()是异步加载,但由于自己的程序确实卡住了这个事实,也没深究为什么异步还会卡住。今后在处理问题时需要更加仔细。

参考资料:

  1. 《PyQt 分离UI主线程与工作线程》http://blog.csdn.net/Mr_Zing/article/details/46945011
  2. 《How do you set up multiple multithreaded QWebViews in PyQt?》http://stackoverflow.com/questions/7143088/how-do-you-set-up-multiple-multithreaded-qwebviews-in-pyqt
版权声明:本文为博主原创文章,未经博主允许不得转载。

Mybatis使用pageHelper分页插件原理

首先在Mybatis的配置文件 SqlMapConfig.xml中配置PageHelper插件 xml version="1.0" encoding="UTF-8" ?> DOCTYPE c...
  • jaryle
  • jaryle
  • 2016年08月25日 16:24
  • 13062

pagehelper 不分页几种情况的解决方法

近期做一个项目,用到了该插件,遇到了些问题,在这里分享一下解决方法 问题一: pagehelper没有效果,一直不能分页问题 解决方法-引用其他博主的博客的解决:http://blog....

Cordova页面加载外网图片失败,Refused to load the image

1.使用Cordova页面加载外网图片失败,抛出异常 Refused to load the image 'http://xxx.png' because it violates the follo...

AsyncTask 异步多线程加载Demo

  • 2014年06月19日 10:04
  • 1.27MB
  • 下载

双缓存多线程加载数据

  • 2012年09月05日 09:45
  • 63KB
  • 下载

AsyncTask 异步多线程加载(有可运行Demo)

AsyncTask 异步多线程加载            编写AsyncTask实现类: 一.  AsyncTask三个参数意义: 参数1:调用execute时所传递的参数 也就是doInBa...

使用多线程加载数据进度窗体

  • 2010年02月10日 00:42
  • 171KB
  • 下载

android ViewPager 简单多线程加载本地图片

在自己做一个简单的APP过程中,使用了ViewPager这一部件来实现图片轮播,在轮播过程中出现了很多问题,比如说掉帧的问题,也就是在加载图片时UI进程做了太多的操作导致skip.接下来就来探讨一下这...

Android ListView&异步加载的学习(二)——多线程加载图片

获取Json数据并转换存入NewsBean类对象之后,由于加载图片不同于文字,加载需要时间,因此用到加载图片的方法,有:1、多线程加载;2、异步加载。 方法一:多线程加载 ----新建ImageL...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:一次失败的QThread多线程加载Webpage.load()页面的尝试
举报原因:
原因补充:

(最多只允许输入30个字)