【发布时间】:2014-07-13 05:47:36
【问题描述】:
我有一个多线程套接字程序。我使用 boost 线程池 (http://threadpool.sourceforge.net/) 来执行任务。我在线程池中为每个线程创建一个 TCP 客户端套接字。每当我发送大量数据(例如 500KB(消息大小))时,吞吐量都会显着降低。我检查了我的代码:
1) 可能导致上下文切换的等待 2) 锁/互斥体
例如,一条 500KB 的消息被分成多行,我使用 ::send( ) 通过套接字发送每一行。
typedef std::list< std::string > LinesListType;
// now send the lines to the server
for ( LinesListType::const_iterator it = linesOut.begin( );
it!=linesOut.end( );
++it )
{
std::string line = *it;
if ( !line.empty( ) && '.' == line[0] )
{
line.insert( 0, "." );
}
SendData( line + CRLF );
}
发送数据:
void SendData( const std::string& data )
{
try
{
uint32_t bytesToSendNo = data.length();
uint32_t totalBytesSent = 0;
ASSERT( m_socketPtr.get( ) != NULL )
while ( bytesToSendNo > 0 )
{
try
{
int32_t ret = m_socketPtr->Send( data.data( ) + totalBytesSent, bytesToSendNo );
if ( 0 == ret )
{
throw;
}
bytesToSendNo -= ret;
totalBytesSent += ret;
}
catch( )
{
}
}
}
catch()
{
}
}
客户端套接字中的发送方法:
int Send( const char* buffer, int length )
{
try
{
int bytes = 0;
do
{
bytes = ::send( m_handle, buffer, length, MSG_NOSIGNAL );
}
while ( bytes == -1 && errno == EINTR );
if ( bytes == -1 )
{
throw SocketSendFailed( );
}
return bytes;
}
catch( )
{
}
}
在发送之前调用 ::select() 会导致上下文切换,因为 ::select 可能会阻塞。持有共享互斥锁会导致并行线程等待并切换上下文。这影响了性能。
是否有避免上下文切换的最佳实践,尤其是在网络编程中?我花了至少一周的时间试图找出各种没有运气的工具(vmstat,valgrind 中的 callgrind)。 Linux 上的任何工具都可以帮助测量这些瓶颈吗?
【问题讨论】:
-
您为什么认为上下文切换和/或锁/互斥锁是问题所在?这500KB,是每秒吗?是从一个客户端加载还是从多个客户端聚合加载?另外,没有代码:(
-
> Linux 上的任何工具都可以帮助测量这些瓶颈吗?
perf record -e cs -g -p PID。 perf.wiki.kernel.org/index.php/…。但是,您提供的信息很少,无法确保上下文切换对此负责。 -
@MartinJames 我已经更新了问题以使其更加清晰。我无法共享代码,因为它跨越多个文件。
-
啊哈.... '我使用 ::send( ) 通过套接字发送每一行' 现在我们到了某个地方。
-
请不要告诉我们您一次发送一行并等待应用级确认......
标签: c++ linux multithreading sockets context-switch