【问题标题】:QDatastream too slow?QDatastream 太慢?
【发布时间】:2016-04-26 09:32:45
【问题描述】:

我正在尝试使用 QSharedmemory 在两个进程之间传递多个图像(实际上是一个视频)。目前我正在序列化 QImages 的 QVector 并将其复制到内存中。这可行,但序列化步骤大约需要 99% 的时间。我怎样才能以独立于平台的方式更快地做到这一点?

我的发送代码:

int main(int argc, const char* argv[])
{
QObject *parent;

QString program = "python";
QStringList arguments;
QString programPath(PYSOURCE);
arguments << "-u" << programPath+QString("/test.py");
qDebug() << arguments;

QProcess *pyProcess = new QProcess();
pyProcess->start(program, arguments);

QVector<QImage> images;
//.. fill with some images

auto start = std::chrono::system_clock::now();
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);

// this takes extremely long ~44s for 80mb
out << images;

int size = buffer.size();

QSharedMemory sharedMemory("process_example");
if (!sharedMemory.create(size)) {
    qDebug() << "Unable to create shared memory segment.";
    return 0;
}

qDebug() << "sizeof mem: " << sharedMemory.size() << "bufsize:" << buffer.size();
sharedMemory.lock();


char *to = (char*)sharedMemory.data();
const char *from = buffer.data().data();
memcpy(to, from, qMin(sharedMemory.size(), size));

sharedMemory.unlock();  

qDebug() << "image copied to shared memory";
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start);
qDebug() << "duration:" << duration.count() << "ms";

while (pyProcess->waitForReadyRead(-1)){
QByteArray newData = pyProcess->readAllStandardOutput();
QString result = QString::fromLocal8Bit(newData);
qDebug(qPrintable(QString("py:")+result));

}
sharedMemory.detach();

return 0;
}

【问题讨论】:

    标签: c++ image ipc qdatastream qsharedmemory


    【解决方案1】:

    我认为缓冲区的主要问题是它需要多次调整大小。尝试将下层字节数组的大尺寸设置为比您的数据需要更大的尺寸。

    buffer.buffer ().resize (100000000);
    

    在图像序列化之前调用它。

    【讨论】:

    • 这对我的测试没有显着影响。我怀疑实际序列化效率低下,一个简单的 memcpy 就足够了,但我不确定如何处理图像标题等。
    【解决方案2】:

    尝试使用QImage.save 将其作为“PNG”保存到QByteArray,然后使用memcpy 将其中的数据复制到QSharedMemory

    http://doc.qt.io/qt-4.8/qimage.html#save-2

    【讨论】:

    • 不幸的是,png 压缩对于我的应用程序来说太慢了(它和数据流编码一样慢)。我现在将原始字节写入内存,这可行,但占用的空间比压缩数据多 30 倍
    【解决方案3】:

    几天前我遇到了同样的问题。我在网上找不到答案,所以我试着自己写代码。方法是直接将图像的原始数据复制到共享内存和从共享内存中复制。这个方法非常非常快。

    图片发送函数:

    //The image-file names are stored in a QStringList object
    void SendImage(QStringList fileList)
    {
        if (sharedMemory.isAttached())
            sharedMemory.detach();
        int count = fileList.count();
        int totalSize = 0;
        QList<QImage> images;
        
        //Load the images
        for (int i = 0; i < count; i++)
        {
            QImage image(fileList.at(i));
            images.append(image);
            totalSize += image.sizeInBytes();
        }
        //Total size needed for shared memory
        totalSize += (count * 5 + 1) * sizeof(int);
        if (!sharedMemory.create(totalSize)) {
            throw QString( "Shared memory cannot be allocated!");
            return;
        }
        sharedMemory.lock();
        
        //to points to the target space to write
        uchar *to = (uchar *)sharedMemory.data();
        //from points to the source to write
        uchar *from = (uchar *)&count;
        
        //Write the count of the images from the first byte of the shared memory
        memcpy(to, from, sizeof(int));
        //Move the pointer forward
        to += sizeof(int);
        
        //Write the images one by one
        for (int i = 0; i < count; i++) {
            //Write the total size of the image and move the pointer forward
            int sizeInBytes = images.at(i).sizeInBytes();
            from = (uchar *)&sizeInBytes;
            memcpy(to, from ,sizeof(int));
            to += sizeof(int);
            
            //Write the width of the image and move the pointer forward
            int width = images.at(i).width();
            from = (uchar *)&width;
            memcpy(to, from ,sizeof(int));
            to += sizeof(int);
            
            //Write the height of the image and move the pointer forward
            int height = images.at(i).height();
            from = (uchar *)&height;
            memcpy(to, from ,sizeof(int));
            to += sizeof(int);
            
            //Write the image format of the image and move the pointer forward
            int imageFormat =  (int)images.at(i).format() ;
            from = (uchar *)&imageFormat;
            memcpy(to, from ,sizeof(int));
            to += sizeof(int);
            
            //Write the bytes per line of the image and move the pointer forward
            int bytesPerLine = images.at(i).bytesPerLine();
            from = (uchar *)&bytesPerLine;
            memcpy(to, from ,sizeof(int));
            to += sizeof(int);
            
            //Write the raw data of the image and move the pointer forward
            from = (uchar *)images.at(i).bits();
            memcpy(to, from, sizeInBytes);
            to += sizeInBytes;
        }
        sharedMemory.unlock();
    }
    

    我接收图片的代码:

    QList<QImage> * FetchImages()
    {
        QList<QImage> * imageList = new QList<QImage>;
        
        if (!sharedMemory.attach())
        {
            throw QString("The shared memory cannot be attached!");
            return imageList;
        }
        
        sharedMemory.lock();
        //from points to the first byte of the shared memory
        uchar * from = (uchar *)sharedMemory.data();
        //Get the count of the images and move the pointer forward
        int count;
        count = *(int *)from;
        from += sizeof(int);
        //Get the images one by one
        for (int i = 0; i < count; i++)
        {
            //Get the size of the image and move the pointer forward
            int sizeInBytes = *(int *)from;
            from += sizeof(int);
            
            //Get the width of the image and move the pointer forward
            int width = *(int *)from;
            from += sizeof(int);
            
            //Get the height of the image and move the pointer forward
            int height  = *(int *)from;
            from += sizeof(int);
            
            //Get the image format of the image and move the pointer forward
            int imageFormat = *(int *)from;
            from += sizeof(int);
            
            ////Get the bytes per line of the image and move the pointer forward
            int bytesPerLine = *(int *)from;
            from += sizeof(int);
    
            //Generate an image using the raw data and move the pointer forward
            QImage image(from, width, height, bytesPerLine, (QImage::Format)imageFormat);
            from += sizeInBytes;
            
            //It is very important here and I spent much time.
            //A new image object "image1" must be deeply copied from "image" before appended to the imageList.
            //Because the raw data of "image" use the space of the shared memory, which will not be accessed after the shared memory is detached.
            //The raw data of the newly constructed "image1" use the memory of its own process.
            QImage image1 = image.copy(0, 0, width, height);
            imageList -> append(image1);
        }
        sharedMemory.unlock();
        sharedMemory.detach();
    
        return imageList;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-02-12
      • 2012-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多