Question

Voici mon problème, j'ai un sqlite memory database en utilisant QSql. J'ai plusieurs threads traitant chacun une table différente de cette base de données commune. Et j'utilise Win API pour m'assurer que ces threads fonctionnent sur différents processeurs, comme ceci:

SetThreadAffinityMask (hThread, processorMask);

Lorsqu'il n'y a qu'un seul thread pour gérer une table, cela prend 10 secondes et utilise 25% du CPU total. Mais quand il y a 4 threads gérant 4 tables différentes, cela prend près de 40 secondes et n'utilise que 35% du CPU total. Je pense que la raison en est qu'il existe une sorte de synchronisation thread-safe dans une base de données. Mais en raison de différents threads de lecture ou d'écriture de tables différentes, thread-safe ralentit mon programme. Comment puis-je l'optimiser?

Mise à jour: La raison la plus possible est que certains types de verrouillage à l'intérieur de Qt ou / et Sqlite 3 ralentit mon programme, il est donc possible d'arrêter ou de contourner ces verrous par pré-configuration.

Update2: Voici un exemple. (Peut-être un peu long, désolé)

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();
}
Était-ce utile?

La solution

Tout d'abord, ne définissez pas le masque d'affinité explicitement, Windows allouera automatiquement les threads sur les cœurs les plus inactifs.Il est préférable de s'appuyer sur le système d'exploitation pour faire la distribution de threads que votre code dans ce cas.

Autant que je sache, sqlite verrouille toute la base de données lors de l'écriture, c'est pourquoi vous n'obtenez pas une amélioration des performances que vous attendiez.Consultez la documentation sur le verrouillage sqlite http://www.sqlite.org/lockingv3.html

Autres conseils

Avez-vous mesuré le temps que les threads passent sur le processeur par rapport, par exemple, au débit d'E / S disque?

Cela n'a rien à voir avec les threads et les verrous.Cela pourrait avoir tout à voir avec la loi d'Amdahl .

Les documents Qt sont sans ambiguïté à ce sujet.Depuis http://doc.qt.nokia.com/4.7/threads-modules.html#threads-and-the-sql-module :

Les threads et le module SQL

Une connexion ne peut être utilisée qu'à partir du thread qui l'a créée. Déplacer des connexions entre des threads ou créer des requêtes à partir d'un un fil différent n'est pas pris en charge.

De plus, les bibliothèques tierces utilisées par les QSqlDrivers peuvent imposer des restrictions supplémentaires sur l'utilisation du module SQL dans un environnement multithread programme.Consultez le manuel de votre client de base de données pour en savoir plus informations

Il n'y a aucun moyen de faire ce que vous voulez via l'API Qt.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top