私有队列上的GCD块停止执行大型SQLite3数据库

时间:2013-12-18 15:31:02

标签: c++ ios ios6 sqlite grand-central-dispatch

我有一个如下创建的串行队列:

self.myQueue = dispatch_queue_create("com.myDomain.myQueue", DISPATCH_QUEUE_SERIAL);

我有一个sqlite3数据库来存储我的数据。我不是每次都提交这些数据,而是每次获得一个数据时,都将其存储在一个缓冲区中 - 在这种情况下,是一个较低级别的基于CPP的“矢量”。

我将块添加到我的私有队列中以写入缓冲区。我使用dispatch_async()来做到这一点。在预定义的时间间隔之后,我将数据从缓冲区提交给DB。

当数据库低于5MB时,事情按预期工作 - 每个数据都进入,每个数据写入缓冲区,在时间间隔到期后,数据从缓冲区提交给数据库。

当DB大小增加到大于5 MB(大约)时,队列上的块似乎要等到将数据提交到DB的时间间隔才会执行。完成此时间后,会将一条记录写入缓冲区。下一次,时间间隔到期,数据被提交给DB,并且只有一条记录被写入缓冲区 - 这次是一个不同的记录,它在序列中我希望记录进入。 看起来每个块只有在我写入DB之后才会执行,只有在每次定义的时间间隔内才会执行。

注意:我已经检查过这些执行的块,干净地执行 - 没有错误。

我无法理解数据库的大小与私有队列上的块的非执行(如果有这样的话)之间的链接。

私人队列的线程宽度是否与它有关?还是内存问题?我会说DB的大小,但似乎每个时间间隔块正确执行。另外,我会直接说DB大小,但我无法写入缓冲区本身。

任何让我指点的想法或者这是一个不受我操控的操作系统问题吗?

1 个答案:

答案 0 :(得分:1)

你是如何设置的还不是很清楚:听起来你有一个使用串行队列保护并发访问的向量。然后听起来你也在同一个队列上进行定期数据库操作。由于它是一个串行队列,如果数据库操作开始花费的时间越来越长,其他操作将在数据库操作后面进行备份。我建议仅将队列用于vector上的基本操作,并使用第二个队列来管理数据库操作。它可能看起来像这样:

using namespace std;

dispatch_queue_t vectorQueue = NULL;
dispatch_queue_t dbQueue = NULL;
dispatch_source_t timer = NULL;
vector<whatever>* dbRecords = NULL;

void init()
{
    dbRecords = new vector<whatever>();
    vectorQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
    dbQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dbQueue);
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, NSEC_PER_SEC * 60, NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
        __block vector<whatever>* toCommit = NULL;
        dispatch_sync(vectorQueue, ^{
            if (dbRecords->size())
            {
                toCommit = new vector<whatever>(*dbRecords);
                dbRecords->clear();
            }
        });

        if (toCommit)
        {
            // Commit the records using your db code...

            delete toCommit;
        }
    });
    dispatch_resume(timer);
}

void enqueueRecord(whatever record)
{
    dispatch_async(vectorQueue, ^{
        dbRecords->push_back(record);
    });
}

这样,不会备份传入的记录块,等待数据库操作。在vectorQueue上执行的唯一块是对共享向量的操作。在提交数据库的时候,将共享向量中的记录复制到私有副本中,清除共享向量,并将私有副本发送到dbQueue以提交。