递归函数严重降低性能?

时间:2014-09-09 22:44:06

标签: c++ multithreading recursion stringstream

我有一个函数,我无限次地调用(或直到满足条件)。这种递归函数的问题在于,在更高级别上,它由工作线程调用,该工作线程推送并弹出一个双端队列。与此同时,我正在使用主线程迭代文件,这比递归函数快得多,递归函数处理从迭代通过主循环检索的数据。下面是严重减慢速度的代码示例如下:

bool CCapsule::DecodeElementList( ElementList &elementList, char* pszBuffer, unsigned int uiBufferLength, std::string strSrcAddress, std::string strDestAddress, std::vector<std::string> &vsContents, bool bIsInner )
{
    // Create an buffer to contain pszBuffer.
    RBuffer rBuffer;
    rBuffer.data = pszBuffer;

    // Create an RElement List and Element Entry to store elements
    RRet rRet;

    RElementEntry rElementEntry;

    // Decode Element List
    if(rDecodeElementList(&m_rDecodeIter, &rElementList, 0) >= RET_SUCCESS)
    {
        std::vector<std::string> _vsContents;
        while ((RRet = rDecodeElementEntry(&m_rDecodeIter, &rElementEntry)) != RRET_END_OF_CONTAINER)
        {
            if (RRet < RET_SUCCESS)
            {
                return false;
            }

            std::string strEntryName = "";

            if (rElementEntry.data != NULL)
                rElementEntry.data;

            switch(rElementEntry.dataType)
            {
            case R_MSG:
                // Create a new RCapsule to encapsulate the inner message.
                m_pInnerMessage = new CCapsule();
                if ( false == m_pInnerMessage->Load( pszBuffer, uiBufferLength, strSrcAddress, strDestAddress, _vsContents, true ) )
                {
                    // An error occurred, clean up.
                    delete m_pInnerMessage;
                    m_pInnerMessage = 0;
                    return false;
                }
                break;
            case R_ELEMENT_LIST:
                // Decode Element List
                RElementList rInnerElementList;
                DecodeElementList(rInnerElementList, pszBuffer, uiBufferLength, strSrcAddress, strDestAddress, _vsContents, true);
                break;
            case R_FIELD_LIST:
                // Decode Field List
                DecodeFieldList(pszBuffer, uiBufferLength);
                break;
            case R_DATE:
                {
                    // Decode DATE
                    RDate rDate;
                    RRet = rDecodeDate( &m_rDecodeIter, &rDate );
                    if ( RRet != RET_SUCCESS )
                    {
                        return false;
                    }
                    std::stringstream sstream;
                    sstream << static_cast<int>( rDate.day ) << "/" << static_cast<int>( rDate.month ) << "/" << rDate.year;
                    _vsContents.push_back(sstream.str());
                }
                break;
            case R_DATETIME:
                {
                    // Decode DATETIME
                    RDateTime rDateTime;
                    RRet = rDecodeDateTime( &m_rDecodeIter, &rDateTime );
                    if ( RRet != RET_SUCCESS )
                    {
                        return false;
                    }

                    RBuffer rStringBuffer;
                    RRet = rDateTimeToString( &rStringBuffer, R_DATETIME,  &rDateTime );
                    if ( RRet != RET_SUCCESS )
                    {
                        return false;
                    }

                    std::stringstream sstream;
                    sstream << static_cast<int>( rDateTime.date.day ) << "/" << static_cast<int>( rDateTime.date.month ) << "/" << static_cast<int>( rDateTime.date.year) << " " << static_cast<int>( rDateTime.time.hour )
                        << ":" << static_cast<int>( rDateTime.time.minute ) << ":" << static_cast<int>( rDateTime.time.second ) << "." << static_cast<int>( rDateTime.time.millisecond ); 
                    _vsContents.push_back(sstream.str());
                }
                break;
            case R_DOUBLE:
                // Decode DOUBLE
                RDouble rDouble;
                RRet = rDecodeDouble( &m_rDecodeIter, &rDouble );
                _vsContents.push_back(boost::lexical_cast<std::string>(rDouble));
                //m_sStringStream << rDouble << ",";
                break;
            case R_UINT:
                // Decode UINT
                RUInt rUInt;
                RRet = rDecodeUInt( &m_rDecodeIter, &rUInt );
                _vsContents.push_back(boost::lexical_cast<std::string>(rUInt));
                //m_sStringStream << rUInt << ",";
                break;
            case R_ASCII_STRING:
                {
                // Decode STRING
                RBuffer rStringBuffer;
                RRet = rDecodeBuffer( &m_rDecodeIter, &rStringBuffer );
                std::string strData(rStringBuffer.data);
                _vsContents.push_back(strData);
                //m_sStringStream << rStringBuffer.data << ",";
                }
                break;
            case R_NO_DATA:
                RRet = RET_SUCCESS;
                break;
            default:
                RRet = RET_FAILURE;
                break;
            }
        }

        std::stringstream ssReport;
        std::copy(_vsContents.cbegin(),_vsContents.cend(),std::ostream_iterator<std::string>(ssReport,","));
        vsContents.push_back(ssReport.str());

    }
    else
    {
        return false;
    }
    return true;
}

不幸的是,它必须按照这个顺序排列,因为存储的字符串向量将包含逗号分隔元素的列表,我将稍后输出到csv列表。这段代码只是解码某些元素并将结果字符串推回到字符串向量中,然后将其放入字符串流中。

有没有人对如何提高性能有任何建议?感谢...

3 个答案:

答案 0 :(得分:3)

递归本身对性能没有影响。您的性能问题将更为传统,例如:

  • 使用分析器来衡量效果。如果您将事物拆分为多个函数(例如,您在此处读取的每种数据类型一个),这会更容易。
  • 验证(使用分析器或其他一些计时器)问题确实存在于您发布的代码中,而不是它调用的代码。我们看不到这些函数中的一半,很可能是它们占用了大部分处理时间,从这个函数中重复调用。
  • 首选重用旧对象来创建新对象,并且更喜欢堆栈分配的对象堆积分配的对象,因为内存管理很昂贵。
  • 在填充之前在std :: vectors中保留空间,以减少在向其添加项目时重新分配和复制的数量。
  • 在您使用它们的范围内初始化对象(例如,将rRet移动到if语句中)以避免支付初始化永不使用的对象的成本
  • 在检查性能之前检查错误。诸如if (rElementEntry.data != NULL) rElementEntry.data;等荒谬的陈述不会做任何有用的事情,但它们可能会花费你的CPU周期。
  • 将字符串格式化的std :: stringstream替换为像sprintf更快的东西。是的,我知道它更危险,但它几乎总是更快。只是要小心并使用更安全的版本,如snprintf或您的平台等效。 lexical_cast也是如此,对不起。
  • 如果你绝对必须使用std :: stringstream,那么使用std :: ostringstream - 你不需要istream部分,对吗?

答案 1 :(得分:1)

通过将通常传递给递归函数的参数推送到堆栈,您可以尝试通过迭代算法替换递归算法。

喜欢的东西:

Stack<Object> stack = new Stack<Object>;
stack.push(first_object);
while( !stack.isEmpty() ) {

   // Do something

     my_object = stack.pop();

  // Push other objects on the stack.
}

这种技术称为递归消除。 检查此链接。

http://cs.saddleback.edu/rwatkins/CS2B/Lab%20Exercises/Stacks%20and%20Recursion%20Lab.pdf

答案 2 :(得分:0)

我觉得你的代码中有两件事是重要的:

  1. 您的算法在n分支树中的图形或预订行程中看起来像DFS。所以应该有一种简单的方法以迭代的方式完成它。对于图形或树中的每个节点,您可以为其定义单独的Access()方法,并使代码更清晰。
  2. 离开小溪并使用snprintf作为@Kylotan建议。
  3. 以上更改可以使您的代码比以前更快。如果它仍然无法满足您的标准,那么您需要尝试一些分析工具。