ultimas sobre por noticias noticia hoy hijo asignacion anses c++ stack heap new-operator automatic-storage

c++ - sobre - ¿Por qué es la asignación en el montón más rápida que la asignación en la pila?



ultimas noticias de anses asignacion universal por hijo 2018 (3)

En lo que respecta a mi conocimiento sobre la gestión de recursos, asignar algo en el montón (operador new ) siempre debe ser más lento que asignar en la pila (almacenamiento automático), ya que la pila es una estructura basada en LIFO, por lo que requiere una contabilidad mínima, y El puntero de la siguiente dirección a asignar es trivial.

Hasta ahora tan bueno. Ahora mira el siguiente código:

/* ...includes... */ using std::cout; using std::cin; using std::endl; int bar() { return 42; } int main() { auto s1 = std::chrono::steady_clock::now(); std::packaged_task<int()> pt1(bar); auto e1 = std::chrono::steady_clock::now(); auto s2 = std::chrono::steady_clock::now(); auto sh_ptr1 = std::make_shared<std::packaged_task<int()> >(bar); auto e2 = std::chrono::steady_clock::now(); auto first = std::chrono::duration_cast<std::chrono::nanoseconds>(e1-s1); auto second = std::chrono::duration_cast<std::chrono::nanoseconds>(e2-s2); cout << "Regular: " << first.count() << endl << "Make shared: " << second.count() << endl; pt1(); (*sh_ptr1)(); cout << "As you can see, both are working correctly: " << pt1.get_future().get() << " & " << sh_ptr1->get_future().get() << endl; return 0; }

Los resultados parecen contradecir lo explicado anteriormente:

Regular: 6131

Hacer compartir: 843

Como puede ver, ambos funcionan correctamente: 42 y 42

Programa finalizado con código de salida: 0

En la segunda medición, aparte de la llamada del operador new , el constructor de std::shared_ptr ( auto sh_ptr1 ) debe finalizar. Parece que no puedo entender por qué esto es más rápido que la asignación regular.

¿Cuál es la explicación para esto?


El problema es que la primera llamada al constructor de std::packaged_task es responsable de inicializar una carga de estado por subproceso que luego se atribuye injustamente a pt1 . Este es un problema común de la evaluación comparativa (especialmente de la marca de microbado) y se alivia con el calentamiento; intenta leer ¿Cómo escribo un micro-benchmark correcto en Java?

Si copio su código pero ejecuto ambas partes primero, los resultados son los mismos dentro de los límites de la resolución del reloj del sistema. Esto demuestra otro problema de la marca microbiológica, que debe realizar pequeñas pruebas varias veces para permitir que el tiempo total se mida con precisión.

Con el calentamiento y la ejecución de cada parte 1000 veces, obtengo lo siguiente ( example ):

Regular: 132.986 Make shared: 211.889

La diferencia (aproximadamente 80 ns) concuerda con la regla general de que malloc toma 100 ns por llamada .


Es un problema con su micro-benchmark: si cambia el orden en el que mide el tiempo, obtendría resultados opuestos ( demo ).

Parece que la primera llamada del constructor std::packaged_task causa un gran éxito. Añadiendo un sin hora

std::packaged_task<int()> ignore(bar);

Antes de medir el tiempo soluciona este problema ( demo ):

Regular: 505
Hacer compartir: 937


He probado tu ejemplo en ideone y obtuve un resultado similar al tuyo:

Regular: 67950 Make shared: 696

Entonces revirtí el orden de las pruebas:

auto s2 = std::chrono::steady_clock::now(); auto sh_ptr1 = std::make_shared<std::packaged_task<int()> >(bar); auto e2 = std::chrono::steady_clock::now(); auto s1 = std::chrono::steady_clock::now(); std::packaged_task<int()> pt1(bar); auto e1 = std::chrono::steady_clock::now();

y encontró un resultado opuesto:

Regular: 548 Make shared: 68065

Así que esa no es la diferencia de pila contra pila, sino la diferencia de la primera y la segunda llamada. Tal vez necesites mirar las std::packaged_task internas de std::packaged_task .