Оптимизировать QSql базы данных памяти в многопроцессорном потоке - PullRequest
3 голосов
/ 16 января 2012

Вот моя проблема, у меня есть один sqlite memory database с помощью QSql. У меня есть несколько потоков, каждый из которых обрабатывает одну таблицу из этой общей базы данных. И я использую Win API, чтобы убедиться, что эти потоки работают на другом процессоре, например:

SetThreadAffinityMask (hThread, processorMask);

Когда поток обрабатывает только одну таблицу, это занимает 10 секунд и использует 25% от общего процессорного времени. Но когда 4 потока обрабатывают 4 разные таблицы, это занимает около 40 секунд и использует только 35% общего процессорного времени. Я думаю, причина в том, что в одной базе данных есть какая-то thread-safe синхронизация. Но из-за разных потоков чтения или записи другой таблицы, потокобезопасность замедляет мою программу. Как я могу оптимизировать это.

Обновление: Наиболее вероятная причина заключается в том, что некоторые виды блокировки внутри Qt или / и Sqlite 3 замедляют мою программу, поэтому можно отключить или обойти эти блокировки путем предварительной настройки.

Обновление2: Вот пример. (Может быть, немного долго, извините)

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();
}

Ответы [ 3 ]

1 голос
/ 27 января 2012

Прежде всего, не устанавливайте маску сходства явно, окна автоматически распределяют потоки по большинству незанятых ядер.В этом случае лучше полагаться на ОС, чтобы распределять потоки, чем на код.

Насколько я знаю, sqlite блокирует всю базу данных во время записи, поэтому вы не получите ожидаемого повышения производительности.Посмотрите документацию по блокировке sqlite http://www.sqlite.org/lockingv3.html

0 голосов
/ 27 января 2012

Документы Qt однозначно говорят об этом. От http://doc.qt.nokia.com/4.7/threads-modules.html#threads-and-the-sql-module:

Потоки и модуль SQL

Соединение может использоваться только из потока, который его создал. Перемещение соединений между потоками или создание запросов из другой поток не поддерживается.

Кроме того, сторонние библиотеки, используемые QSqlDrivers, могут наложить дополнительные ограничения на использование модуля SQL в многопоточном программа. Обратитесь к руководству вашего клиента базы данных для получения дополнительной информации. информация

Невозможно сделать то, что вы хотите, через Qt API.

0 голосов
/ 24 января 2012

Вы измерили, сколько времени тратят потоки на процессор по сравнению, скажем, с пропускной способностью дискового ввода-вывода?

Это никак не связано с потоками и блокировками. Это может быть все, что связано с законом Амдала .

...