He trabajado con C++, java y C# implementando un motor de búsqueda similar al de Google para el Departamento de Defensa junto con muchos otros programas que requieren un alto rendimiento (utilizando mapeo de memoria de bajo nivel y named pipes/tcp).
Según mi experiencia, no se puede igualar la velocidad de C++ con el código gestionado. En el código gestionado, cada llamada a new, garbage collection, etc. requiere múltiples búsquedas de memoria para asignar y desasignar memoria. Con cada recolección de basura hay múltiples hilos creados para cada generación de las ubicaciones de memoria (así que si tienes desarrolladores no tan conocedores...). además, cuando estás realizando muchos cambios de hilos o cargando datos en memoria (por ejemplo en flujos de memoria o transferencias a través de tcp/tuberías con nombre) perderás velocidad debido a la necesidad de serialización de los códigos gestionados (puede ser wcf, remoting, servicios web, etc.) no importa que las transferencias de datos en .net sean serializadas a menos que escribas tus propias envolturas tcp/tuberías con nombre. es peor si necesitas usar COM ya que tu código gestionado necesitará envolver todo en envolturas llamables com.
Por último y más importante, no olvides que la mayoría de las librerías .net son envoltorios de la antigua api de win32. .net framework pump sigue traduciendo sus llamadas a la antigua bomba de mensajes de win32 para realizar muchas de sus operaciones (por ejemplo, DllImport("User32",...)). También la librería de sockets de .Net (wcf, remoting, etc.) utiliza la api subyacente tcp/ip y named pipe (por ejemplo, ver la capacidad de WCF de permitirte configurar eitehr named pipes y conexión tcp. Los Namedpipes son como los manejadores de archivos y requieren un acceso de muy bajo nivel, por lo que se les da una simple envoltura).
así que para la velocidad C++; para la facilidad de desarrollo C#/Java. C# puede ser optimizado usando varias tácticas pero requiere de buenos desarrolladores que sepan cómo "manejar" los objetos y la GC (por ejemplo, implementar interfaces para hacer tu propia GC, llamar directamente a la api de win32 cuando sea necesario, suprimir la GC, no usar clases que serialicen y deserialicen al menos tratar de evitarlo, construir tus propias clases de búfer y comprobaciones de crc para facilitar, usar sockets de bajo nivel y no usar wrappers de wcf (a menos que su objetivo sea crear un webservice).