QT 多线程采用线程池进行网络操作

研究内容:

学习爬取网络数据的工程,但是性能上想达到并发效果,一直做线程,没有做线程池并发效果。

处理中发现:

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

(Parent is QNetworkAccessManager(0x21dcba0), parent's thread is QThread(0x20be1c0), current thread is QThread(0x7f48e0044730)

 

 QNetworkAccessManager *manager = new QNetworkAccessManager(this);

  connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));

  manager->get(QNetworkRequest(QUrl("http://qt-project.org")));

参考的这篇文章:

https://www.cnblogs.com/btian/p/6512365.html

使用线程的movethread就不谈了。但是并发的时候我没有想到好的框架,我想用线程池的方式来处理并发问题,因为一个页面一个页面去爬取,5000条要等好久的。

我本次是第一次写这个并发的模型,可能还需要调整。

上面的问题通俗点理解就是在线程里操作网络的时,线程里面创建的对象是子类的,不可以将父类指针在两者之间公用。就是那个THIS。

原来的模型:

class MyNetworkpublic QObject

{

    Q_OBJECT

    public:

        explicit MyNetwork(QObject *parent = nullptr);

        ~MyNetwork();

        void getHtml(QString urlint idQObject *);

        int m_id;

        QString m_url;

    public slots:

        void replyFinished(QNetworkReply *reply);

        void slotReadyRead();

        void slotError(QNetworkReply::NetworkError);

        void dowork();

    private:

        QNetworkAccessManager *m_network;

        QNetworkReply *reply;

        QNetworkRequest * m_request;

    signals:

        void getid(int id,QString msg);

};

#endif // MYNETWORK_H

 

主程序通过线程调用的话:(初学者最好用movethread,为什么?我就是初学者,因为初学者用这个问题比较少,讲太多可能也不方便去感受线程的魅力,那么,可以针对这个问题再深入去研究

QThread *thread = new QThread();

MyNetwork *my = new MyNetwork ();//自己考虑去释放

my->moveToThread(thread);

thread->start();

connect(thread, SIGNAL(started()), my, SLOT(dowork()));

以上:是调用单个线程的,如果有几十个左右的网络请求,一个线程FOR循环多次请求,或多开几个线程都是满足项目需求。

///

多个线程考虑了线程池,然后就想把上面的改成并发的效果,结果可想而知(Parent is QNetworkAccessManager(0x21dcba0), parent's thread is QThread(0x20be1c0), current thread is QThread(0x7f48e0044730)

我在线程里实例化QNetworkAccessManager,信号槽完全没反应,又是一个安静的深夜,搞的我头昏昏的。

这里面有设计到一个知识点

参考文章 :https://blog.csdn.net/xiangjai/article/details/52091544

======================================

此情况下finished信号永远不被触发,在线程外面调用则可正常触发使用,通过查资料终于弄明白,

放在线程内使用QNetworkAccessManager时没有进行线程的事件循环,需要调用exec()才能开启线程的事件循环,

因此解决方式为:get(request)后面加上exec(),使线程进行事件循环。

但是通常很多人还是加不上去。

================================

#include 

#include =

#include 

class URLTaskWorker:public QObjectpublic QRunnable

{

Q_OBJECT

public:

    URLTaskWorker(){

            }

public:

 

public slots:

    void run(){

     

        QEventLoop temp_loop;

         QNetworkAccessManager   qnam1 ;

        this->url = QUrl("http://www.baidu.com");

        QNetworkRequest request(url);

        reply=qnam1.get(request);

       connect(replySIGNAL(finished()), &temp_loopSLOT(quit()));

       temp_loop.exec();

       reply->waitForReadyRead(3);

        qDebug()<<"start";

        if(reply->error()==QNetworkReply::NoError) //这个部分如果能信号出去就更好了,后续再研究

        {

             QByteArray bytes = reply->readAll();

            qDebug()<<bytes.size();

        }

        qDebug()<<"finished";

        reply->deleteLater();

 

        qDebug() << url <<reply;

    };

private:

    QNetworkAccessManager   qnam;

    QUrl                    url;

    QNetworkReply*  reply;

 

 

};

 

#endif // URLTASKWORKER_H

主程序通过线程池调用,达到我的效果:

 QThreadPool pool;

   pool.setMaxThreadCount(5);

 

       for(int i = 0i < m_list.size(); i++)//5000条数据多线程爬取

       {

           URLTaskWorker * net2 = new URLTaskWorker();

           pool.startnet2);

       }

 

你可能感兴趣的:(QT,布局,多线程,window系统)