3

これが私の問題sqlite memory databaseですQSql。この共通データベースの 1 つの異なるテーブルをそれぞれ処理する複数のスレッドがあります。そして、次Win APIのように、これらのスレッドが異なるプロセッサで動作することを確認するために使用します。

SetThreadAffinityMask (hThread, processorMask);

1 つのテーブルを処理するスレッドのみがある場合、10 秒かかり、合計 CPU の 25% を使用します。しかし、4 つの異なるテーブルを処理する 4 つのスレッドがある場合、40 秒近くかかり、合計 CPU の 35% しか使用しません。その理由は、1 つのデータベースに何らかのthread-safe同期があるためだと思います。しかし、異なるテーブルの読み取りまたは書き込みが異なるスレッドが原因で、スレッドセーフは私のプログラムを遅くします。どうすれば最適化できますか。

更新:最も考えられる理由は、プログラム内のある種のロックQtまたは/およびSqlite 3プログラムの速度が低下するため、事前に設定してこれらのロックをシャットダウンまたはバイパスすることは可能ですか.

Update2:例を次に示します。(少し長いかもしれません、すいません)

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

3 に答える 3

1

まず、アフィニティ マスクを明示的に設定しないでください。ウィンドウは、最もアイドル状態のコアにスレッドを自動的に割り当てます。この場合、スレッドの配布はコードよりも OS に依存する方が適切です。

私の知る限り、sqlite は書き込み中にデータベース全体をロックします。sqlite ロックに関するドキュメントhttp://www.sqlite.org/lockingv3.htmlをご覧ください。

于 2012-01-27T09:05:00.137 に答える
0

Qtのドキュメントはこれについて明確です。http://doc.qt.nokia.com/4.7/threads-modules.html#threads-and-the-sql-moduleから:

スレッドと SQL モジュール

接続は、それを作成したスレッド内からのみ使用できます。スレッド間の接続の移動、または別のスレッドからのクエリの作成はサポートされていません。

さらに、QSqlDrivers によって使用されるサード パーティ ライブラリは、マルチスレッド プログラムでの SQL モジュールの使用にさらなる制限を課す可能性があります。詳細については、データベース クライアントのマニュアルを参照してください。

Qt API を介してやりたいことを行う方法はありません。

于 2012-01-27T14:17:58.227 に答える
0

たとえば、ディスク I/O スループットと比較して、スレッドが CPU に費やしている時間を測定しましたか?

これは、スレッド化とロックとは何の関係もない可能性があります。アムダールの法則と関係があるかもしれません。

于 2012-01-24T14:50:27.737 に答える