2012-01-16 4 views
3

ここに私の問題があります。sqlitememory databaseQSqlを使用してください。私は、この共通データベースの異なるテーブルを扱ういくつかのスレッドを持っています。そして私は、これらのスレッドは、このように、異なるプロセッサ上で作業を確認するためにWin APIを使用します。マルチプロセッサスレッドのメモリデータベースのQSqlを最適化する

SetThreadAffinityMask (hThread, processorMask); 

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

更新:最も考えられる理由はそれがシャットダウンすることが可能であるか、事前に設定することにより、これらのロックをバイパスし、私のプログラムを遅く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(); 
} 
+0

これは実際にsqlite3の使い方によって異なります。あなたがデータベースでやっていることのいくつかの例を貼り付けてください。 – synthesizerpatel

+0

最適化を進める前に、この質問を見てください:http://stackoverflow.com/questions/1680249/how-to-use-sqlite-in-a-multi-threaded-application – Neox

+0

@Noxそれは助けをしますが私の状況にはいくつかの違いがあります。私のプログラムでは、 'sqlite'ではなく' QSql'を直接使用していますので、sqlite3のコンパイル方法を選択することはできません。2番目のスレッドは異なるテーブルで実行されているので、スレッド間で同期する必要はありません。私はメモリデータベースを使用するので、私は同じ接続を共有する必要があります。 – xucheng

答えて

1

まずアフィニティマスクを明示的に設定しないでください。ウィンドウは自動的に最も空いているコアにスレッドを割り当てます。この場合、コードよりもスレッドの配布を行うためにOSに頼る方がよいでしょう。

私が知る限り、sqliteは書き込み中にデータベース全体をロックするため、期待したパフォーマンスの向上は得られません。 sqliteロックのドキュメントを見てくださいhttp://www.sqlite.org/lockingv3.html

0

は、あなたがスレッドがに比べ、たとえば、ディスクI/OスループットとCPUの上に費やしているどのくらいの時間を測定しましたか?

これはスレッドとロックとは関係ありません。それはAmdahl's lawと関係があります。

+0

ディスクI/Oはまったくなく、メモリデータベース内の純粋な計算です。 – xucheng

+0

これはディスクではありませんが、それはポイントではありません。 Amdahl効果を引き起こす*あらゆるブロックリソースがあります。 – spraff

0

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

スレッドとSQLモジュール

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

さらに、QSqlDriversで使用されるサードパーティのライブラリ は、マルチスレッドの プログラムでSQLモジュールを使用する際にさらに制限を課すことができます。あなたはQtのAPIを介してやりたいする方法はありませんより多くの 情報

については、データベースクライアントのマニュアルを参照してください。

+0

しかし、私のコードは実行可能なので、私はそれを(QSqlのbtwnスレッドを使用して)行うことができます。私はちょうどそれを最適化する方法を知らない。 – xucheng

+0

要点ですが、これはサポートされていません。プログラムがクラッシュしたり、データが破損したり、何かが起こる可能性があります。概念的に言えば、ロックしないで同じデータベース内の異なるテーブルに同時に書き込むことは意味がありません。あなたのテーブルは関連しているので、ロックが必要です。そうでないと、同じデータベースにいる必要もありません。どちらですか? –