Pergunta

Why is my qtconcurrent::run() call just as slow as calling the member function through the object??

(Ex: QtConcurrent::run(&db, &DBConnect::loadPhoneNumbers) is just as slow as calling db.loadPhoneNumbers())

Read below for futher explanation

I've been trying to create a thread via QtConcurrent::run to help speed up data being sent to a SQL database table. I am taking a member variable which is a QMap and iterating through it to send each key+value to the database.

Member function for the QtConcurrent::run() call:

void DBConnect::loadPhoneNumbers()
{

//m_phoneNumbers is a private QMap member variable in DBConnect
qDebug() << "\t[!] Items to send: " << m_phoneNumbers.size();

QSqlQuery query;
qDebug() << "\t[!] Using loadphonenumbers thread: " << QThread::currentThread();
qDebug() << "\t[!] Ideal Num of Threads: " << QThread::idealThreadCount();

bool isLoaded = false;

QMap<QString,QString>::const_iterator tmp = m_phoneNumbers.constBegin();

while(tmp != m_phoneNumbers.constEnd())
{
    isLoaded = query.exec(QString("INSERT INTO "+m_mtable+" VALUES('%1','%2')").arg(tmp.key()).arg(tmp.value()));

    if(isLoaded == false)
    {
        qDebug() << "\r\r[X] ERROR: Could\'t load number " << tmp.key() << " into table " << m_mtable;
        qDebug() << query.lastError().text();
    }

    tmp++;
}

}

main.cpp section that calls the thread

DBConnect db("QODBC", myINI.getSQLServer(),C_DBASE,myINI.getMTable(), myINI.getBTable());
db.startConnect();

//...more code here

     qDebug() << "\n[*] Using main thread: " << QThread::currentThread() << endl;

         //....two qtconcurrent::run() threads started and finished here (not shown)

         qDebug() << "\n[*] Sending numbers to Database...";
         QFuture<void> dbFuture = QtConcurrent::run(&db, &DBConnect::loadPhoneNumbers);
         dbFuture.waitForFinished();

My understanding of the situation

From my understanding, this thread will run under a new pool of threads seperate from the main thread. What I am seeing is not the case (note there are 2 other QtConcurrent::run() calls before this one for the database, all left to finish before continuing to database call)

Now I thought about using QtConcurrent::map() / mapped() but couldn't get it to work properly with a QMap. (Couldn't find any examples to help out with either but that is besides the matter... was just an FYI in case someone asks why I didn't use one)

Have been doing some "debug" work to find out whats happening and in my tests I use QThread::currentThread() to find which thread I am currently making a call from. This is what is happening for the various threads in my program. (All qtconcurrent::run() calls are made in main.cpp FYI... not sure if that makes a difference)

Check what is main thread: on QThread(0x5d2cd0)
Run thread 1: on QThread(0x5dd238, name = "Thread (pooled)")
Run thread 2: on QThread(0x5d2cd0)
Run thread 3 (loadPhoneNumbers function): on QThread(0x5d2cd0)

As seen above, other than the first qtconcurrent::run() call, everything else is on the main thread (o.O)

Questions:

From my understanding, all my threads (all qtconcurrent::run) should be on their own thread (only first one is). Is that true or am I missing something?

Second, is my loadPhoneNumebrs() member function thread safe?? (Since I am not altering anything from what I can see)

Biggest question: Why is my loadPhoneNumbers() qtconcurrent::run call just as slow as if I just called the member function? (ex: db.loadPhoneNumbers() is just as slow as the qtconcurrent::run() version)

Any help is much appreciated!

Foi útil?

Solução

Threads don't magically speed things up, they just make it so you can continue doing other stuff while it's happening in the background. When you call waitForFinished(), your main thread won't continue until the load phone numbers thread is finished, essentially negating that advantage. Depending on the implementation, that may be why your currentThread() is showing the same as main, because the wait is already happening.

Probably more significant in terms of speed would be to build a single query that inserts all the values in the list, rather than a separate query for each value.

Outras dicas

According to QtSql documentation:

A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread is not supported.

It works anyway because ODBC itself supports multithreaded access to a single ODBC handle. But since you are only using one connection, all queries are probably serialized by ODBC as if there was only a single thread (see for example what Oracle's ODBC driver does).

waitForFinished() calls a private function stealRunnable() that, as its name implies, takes a not yet started task from the QFuture queue an runs it in the current thread.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top