Domanda

Ecco il mio problema, ne ho uno sqlite memory database usando QSql. Ho diversi thread che gestiscono una tabella diversa di questo database comune. E io uso Win API Per assicurarsi che questi thread funzionino su un processore diverso, in questo modo:

SetThreadAffinityMask (hThread, processorMask);

Quando c'è solo un thread che gestisce una tabella, ci vogliono 10 secondi e utilizza il 25% della CPU totale. Ma quando ci sono 4 thread che gestiscono 4 diverse tabelle, ci vogliono quasi 40 secondi e utilizza solo il 35% della CPU totale. Penso che il motivo sia che ci sia una specie di thread-safe Sincronizzazione in un database. Ma a causa della diversa lettura del thread o della scrittura di tabella diversa, thread-safe rallenta il mio programma. Come posso ottimizzarlo.

Aggiornare: La ragione più possibile è un tipo di blocco all'interno di Qt o/e Sqlite 3 rallenta il mio programma, quindi è possibile arrestare o bypassare questi blocchi prefissandosi.

Aggiornamento2: Ecco un esempio. (Forse un po 'lungo, scusa)

class MultiProcessorThread
{
public:
    virtual void run();
    bool start()
    {
        m_hThread = CreateThread (NULL, 0, MultiProcessorThread::ThreadFunc, this, CREATE_SUSPENDED, NULL);

        if (m_hThread != INVALID_HANDLE_VALUE)
        {
            RunningThreadCount++;
            m_ProcessorMask = 1 << ( (RunningThreadCount - 1) % ProcessorCount);
            SetThreadAffinityMask (m_hThread, m_ProcessorMask); // Make thread working on different processor
            ResumeThread (m_hThread);
            return true;
        }
        else
            return false;
    }
protected:
    static DWORD WINAPI ThreadFunc (LPVOID in);
    HANDLE m_hThread;
    DWORD_PTR m_ProcessorMask;
    static DWORD_PTR ProcessorCount;
    static DWORD_PTR RunningThreadCount;
    static DWORD_PTR GetNumCPUs();
};

DWORD_PTR MultiProcessorThread::ProcessorCount = GetNumCPUs();
DWORD_PTR MultiProcessorThread::RunningThreadCount = 0;
DWORD_PTR MultiProcessorThread::GetNumCPUs() // Get how many processors on this PC
{
    SYSTEM_INFO m_si = {0};
    GetSystemInfo (&m_si);
    return (DWORD_PTR) m_si.dwNumberOfProcessors;
}
DWORD WINAPI MultiProcessorThread::ThreadFunc (LPVOID in)
{
    static_cast<MultiProcessorThread*> (in)->run();
    return 0;
}

class Run : public MultiProcessorThread
{
public:
    void run()
    {
        int i = 0;
        QString add = "insert into %1 values(1)";
        add = add.arg (table);
        QString sel = "select a from %1 ";
        sel = sel.arg (table);
        QString del = "delete from %1 where a=1";
        del = del.arg (table);

        while (++i) // read and write database
        {
            query.exec (add);
            query.exec (sel);
            query.exec (del);
        }
    }
    QSqlQuery query;
    QString table;
};  

int main (int argc, char *argv[])
{
    QCoreApplication a (argc, argv);
    QSqlDatabase db = QSqlDatabase::addDatabase ("QSQLITE", "test"); 
    db.setDatabaseName (":memory:"); // All threads working on the same memory database.
    db.open();
    QSqlQuery q (db), q1 (db), q2 (db);
    q.exec ("create table A (a)");
    q1.exec ("create table B (a)");
    q2.exec ("create table C (a)"); // All threads working on different table.
    Run b[3];
    b[0].query = QSqlQuery (q);
    b[0].table = "A";
    b[1].query = QSqlQuery (q1);
    b[1].table = "B";
    b[2].query = QSqlQuery (q2);
    b[2].table = "C";
    b[0].start();
    b[1].start();
    b[2].start();
    return a.exec();
}
È stato utile?

Soluzione

Prima di tutto, non impostare esplicitamente l'affinità maschera, Windows allocherà automaticamente i thread sui core più inattivi. È meglio fare affidamento sul sistema operativo per eseguire la distribuzione dei thread rispetto al codice in questo caso.

Per quanto ne so, SQLite blocca l'intero database durante la scrittura, ecco perché non ottieni un aumento delle prestazioni che ti aspettavi. Dai un'occhiata alla documentazione di blocco SQLite http://www.sqlite.org/lockingv3.html

Altri suggerimenti

Hai misurato quanto tempo i thread stanno spendendo sulla CPU rispetto a, diciamo, la più di throughput del disco?

Questo non potrebbe avere nulla a che fare con il threading e le serrature. Potrebbe avere tutto a che fare con La legge di Amdahl.

I documenti QT non sono ambigui su questo. Da http://doc.qt.nokia.com/4.7/Threads-modules.html#Threads-and-the-Sql-module:

Discussioni e modulo SQL

Una connessione può essere utilizzata solo all'interno del thread che l'ha creata. Non è supportato spostare connessioni tra thread o creare query da un thread diverso.

Inoltre, le librerie di terze parti utilizzate dai QSQLDRiver possono imporre ulteriori restrizioni all'utilizzo del modulo SQL in un programma multithread. Consultare il manuale del client di database per ulteriori informazioni

Non c'è modo di fare quello che vuoi attraverso l'API QT.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top