簡體   English   中英

多線程性能std :: string

[英]Multi-threaded performance std::string

我們在使用OpenMP的項目上運行一些代碼,我遇到了一些奇怪的事情。 我已經包含了一些演示代碼的部分內容,以展示我所看到的內容。

測試比較在多線程循環中使用帶有std :: string參數的const char *參數調用函數。 這些函數基本上什么都不做,所以沒有開銷。

我所看到的是完成循環所需時間的主要差異。 對於執行100,000,000次迭代的const char *版本,代碼需要0.075秒才能完成,而std :: string版本需要5.08秒。 這些測試是在帶有gcc-4.4的Ubuntu-10.04-x64上完成的。

我的問題基本上是否這完全是由於std :: string的動態分配以及為什么在這種情況下無法優化掉,因為它是const並且不能改變?

以下代碼,非常感謝您的回復。

編譯:g ++ -Wall -Wextra -O3 -fopenmp string_args.cpp -o string_args

#include <iostream>
#include <map>
#include <string>
#include <stdint.h>

// For wall time
#ifdef _WIN32
#include <time.h>
#else
#include <sys/time.h>
#endif

namespace
{
  const int64_t g_max_iter = 100000000;
  std::map<const char*, int> g_charIndex = std::map<const char*,int>();
  std::map<std::string, int> g_strIndex = std::map<std::string,int>();

  class Timer
  {
  public:
    Timer()
    {
    #ifdef _WIN32
      m_start = clock();
    #else /* linux & mac */
      gettimeofday(&m_start,0);
    #endif
    }

    float elapsed()
    {
    #ifdef _WIN32
      clock_t now = clock();
      const float retval = float(now - m_start)/CLOCKS_PER_SEC;
      m_start = now;
    #else /* linux & mac */
      timeval now;
      gettimeofday(&now,0);
      const float retval = float(now.tv_sec - m_start.tv_sec) + float((now.tv_usec - m_start.tv_usec)/1E6);
      m_start = now;
    #endif
      return retval;
    }

  private:
    // The type of this variable is different depending on the platform
#ifdef _WIN32
    clock_t
#else
    timeval
#endif
    m_start;   ///< The starting time (implementation dependent format)
  };

}

bool contains_char(const char * id)
{
  if( g_charIndex.empty() ) return false;
  return (g_charIndex.find(id) != g_charIndex.end());
}

bool contains_str(const std::string & name)
{
  if( g_strIndex.empty() ) return false;
  return (g_strIndex.find(name) != g_strIndex.end());
}

void do_serial_char()
{
  int found(0);
  Timer clock;
  for( int64_t i = 0; i < g_max_iter; ++i )
  {
    if( contains_char("pos") )
    {
     ++found;
    }
  }
  std::cout << "Loop time: " << clock.elapsed() << "\n";
  ++found;
}

void do_parallel_char()
{
  int found(0);
  Timer clock;
#pragma omp parallel for
  for( int64_t i = 0; i < g_max_iter; ++i )
  {
    if( contains_char("pos") )
    {
     ++found;
    }
  }
  std::cout << "Loop time: " << clock.elapsed() << "\n";
  ++found;
}

void do_serial_str()
{
  int found(0);
  Timer clock;
  for( int64_t i = 0; i < g_max_iter; ++i )
  {
    if( contains_str("pos") )
    {
     ++found;
    }
  }
  std::cout << "Loop time: " << clock.elapsed() << "\n";
  ++found;
}

void do_parallel_str()
{
  int found(0);
  Timer clock;
#pragma omp parallel for
  for( int64_t i = 0; i < g_max_iter ; ++i )
  {
    if( contains_str("pos") )
    {
     ++found;
    }
  }
  std::cout << "Loop time: " << clock.elapsed() << "\n";
  ++found;
}

int main()
{
  std::cout << "Starting single-threaded loop using std::string\n";
  do_serial_str();
  std::cout << "\nStarting multi-threaded loop using std::string\n";
  do_parallel_str();

  std::cout << "\nStarting single-threaded loop using char *\n";
  do_serial_char();
  std::cout << "\nStarting multi-threaded loop using const char*\n";
  do_parallel_char();
  }

我的問題基本上是否這完全是由於std :: string的動態分配以及為什么在這種情況下無法優化掉,因為它是const並且不能改變?

是的,這是由於每次迭代時std :: string的分配和復制。

一個足夠聰明的編譯器可能會對此進行優化,但目前的優化器不太可能發生這種情況。 相反,你可以自己提升弦:

void do_parallel_str()
{
  int found(0);
  Timer clock;
  std::string const str = "pos";  // you can even make it static, if desired
#pragma omp parallel for
  for( int64_t i = 0; i < g_max_iter; ++i )
  {
    if( contains_str(str) )
    {
      ++found;
    }
  }
  //clock.stop();  // Or use something to that affect, so you don't include
  // any of the below expression (such as outputing "Loop time: ") in the timing.
  std::cout << "Loop time: " << clock.elapsed() << "\n";
  ++found;
}

改變:

if( contains_str("pos") )

至:

static const std::string str = "pos";
if( str )

改變了很多東西? 我目前最好的猜測是,每個循環的std::string隱式構造函數調用會引入相當大的開銷並盡可能地優化它,但我懷疑這仍然是一個足夠困難的問題。

std::string (在你的情況下是臨時的)需要動態分配,與循環中的其他所有內容相比,這是一個非常慢的操作。 COW也有標准庫的舊實現,在多線程環境中也會變慢。 話雖如此,沒有理由為什么編譯器不能優化臨時字符串創建並優化掉整個contains_str函數調用,除非你有一些副作用。 由於您沒有為該功能提供實現,因此無法確定它是否可以完全優化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM