Información general sobre el runtime de simultaneidad

En este documento se proporciona información general sobre el runtime de simultaneidad. Se describen las ventajas del runtime de simultaneidad, cuándo usarlo, y cómo interactúan sus componentes entre sí y con el sistema operativo y las aplicaciones.

Secciones

Este documento contiene las siguientes secciones:

  • Por qué es importante un runtime para simultaneidad

  • Arquitectura

  • Expresiones lambda de C++

  • Requisitos

Por qué es importante un runtime para simultaneidad

Un runtime de simultaneidad proporciona uniformidad y previsibilidad a las aplicaciones y los componentes de aplicación que se ejecutan simultáneamente. Dos ejemplos de las ventajas del Runtime de simultaneidad son la programación de tareas cooperativa y el bloqueo cooperativo.

El Runtime de simultaneidad usa un programador de tareas cooperativo que implementa un algoritmo de robo de trabajo para distribuir el trabajo de forma eficaz entre los recursos informáticos. Por ejemplo, considere una aplicación que tiene dos subprocesos, ambos administrados por el mismo runtime. Si un subproceso finaliza su tarea programada, puede descargar de trabajo al otro subproceso. Este mecanismo equilibra la carga de trabajo total de la aplicación.

El Runtime de simultaneidad también proporciona primitivas de sincronización que utilizan el bloqueo cooperativo para sincronizar el acceso a los recursos. Por ejemplo, considere una tarea que debe tener acceso exclusivo a un recurso compartido. Mediante un bloqueo cooperativo, el runtime puede usar el cuanto restante para realizar otra tarea mientras la primera espera por el recurso. Este mecanismo promueve el uso máximo de los recursos.

[Ir al principio]

Arquitectura

El Runtime de simultaneidad se divide en cuatro componentes: la Biblioteca de modelos de procesamiento paralelo (PPL), la Biblioteca de agentes asincrónicos, el Programador de tareas y el Administrador de recursos. Estos componentes se encuentran entre el sistema operativo y las aplicaciones. La siguiente ilustración muestra cómo interactúan los componentes del Runtime de simultaneidad entre el sistema operativo y las aplicaciones:

Arquitectura del Runtime de simultaneidad

La arquitectura del Runtime de simultaneidad

El Runtime de simultaneidad resulta altamente ajustable, es decir, se puede combinar la funcionalidad existente para conseguir más. El Runtime de simultaneidad crea muchas características, como los algoritmos paralelos, a partir de los componentes de nivel inferior.

El Runtime de simultaneidad también proporciona primitivas de sincronización que utilizan el bloqueo cooperativo para sincronizar el acceso a los recursos. Para obtener más información sobre estas primitivas de sincronización, vea Estructuras de datos de sincronización.

En las siguientes secciones se proporciona una información general de lo que cada componente proporciona y cuándo utilizarlo.

Biblioteca de modelos de procesamiento paralelo

La Biblioteca de modelos de procesamiento paralelo (PPL) proporciona contenedores y algoritmos de uso general para realizar un paralelismo específico. Esta biblioteca habilita el paralelismo de datos imperativo, ya que proporciona algoritmos paralelos que distribuyen los cálculos en colecciones o en conjuntos de datos entre recursos. También habilita el paralelismo de tareas mediante objetos de tarea que distribuyen varias operaciones independientes entre los recursos.

Utilice la Biblioteca de modelos de procesamiento paralelo si cuenta con un cálculo local que se puede beneficiar de la ejecución paralela. Por ejemplo, puede usar el algoritmo Concurrency::parallel_for para transformar un bucle for existente de forma que actúe en paralelo.

Para obtener más información sobre la Biblioteca de modelos de procesamiento paralelo, vea Parallel Patterns Library (PPL).

Biblioteca de agentes asincrónicos

La Biblioteca de agentes asincrónicos (o simplemente Biblioteca de agentes) proporciona un modelo de programación basado en actores e interfaces de paso de mensajes para las tareas genéricas de flujo de datos y canalización. Los agentes asincrónicos permiten realizar un uso productivo de la latencia ya que realizan el trabajo mientras otros componentes esperan datos.

Utilice la Biblioteca de agentes si dispone de varias entidades que se comunican entre sí de forma asincrónica. Por ejemplo, puede crear un agente que lea datos de un archivo o una conexión de red y que, a continuación, use las interfaces de paso de mensajes para enviar estos datos a otro agente.

Para obtener más información sobre la Biblioteca de agentes, vea Biblioteca de agentes asincrónicos.

Programador de tareas

El Programador de tareas programa y coordina las tareas en tiempo de ejecución. El Programador de tareas es cooperativo y utiliza un algoritmo de robo de trabajo para lograr el uso máximo de los recursos de procesamiento.

El Runtime de simultaneidad proporciona un programador predeterminado para que no tenga que controlar los detalles de infraestructura. Sin embargo, para satisfacer las necesidades de calidad de la aplicación, también puede proporcionar una directiva propia de programación o asociar programadores concretos con tareas concretas.

Para obtener más información sobre el Programador de tareas, vea Programador de tareas (Runtime de simultaneidad).

Administrador de recursos

El Administrador de recursos desempeña el rol de administrar los recursos informáticos, como los procesadores y la memoria. Responde a las cargas de trabajo a medida que cambian en tiempo de ejecución mediante la asignación de recursos allí donde pueden resultar más eficaces.

El Administrador de recursos actúa como una abstracción sobre los recursos e interactúa principalmente con el Programador de tareas. Si bien se puede utilizar el Administrador de recursos para ajustar el rendimiento de las bibliotecas y aplicaciones, por lo general se usa la funcionalidad que proporcionan la Biblioteca de modelos de procesamiento paralelo, la Biblioteca de agentes y el Programador de tareas. Estas bibliotecas usan el Administrador de recursos para volver a equilibrar de forma dinámica los recursos a medida que cambian las cargas de trabajo.

[Ir al principio]

Expresiones lambda de C++

Muchos de los tipos y algoritmos que se definen en el Runtime de simultaneidad se implementan como plantillas de C++. Algunos de estos tipos y algoritmos toman como parámetro una rutina que realiza trabajo. Este parámetro puede ser una función lambda, un objeto de función o un puntero a una función. Estas entidades también se conocen como funciones de trabajo o rutinas de trabajo.

Las expresiones lambda son una característica nueva e importante del lenguaje Visual C++ porque proporcionan una manera concisa de definir funciones de trabajo para el procesamiento paralelo. Los objetos de función y los punteros a función permiten usar el runtime de simultaneidad con el código existente. Sin embargo, se recomienda usar expresiones lambda al escribir código nuevo debido a las ventajas de seguridad y productividad que proporcionan.

En el ejemplo siguiente se compara la sintaxis de las funciones lambda, los objetos de función y los punteros a función en varias llamadas al algoritmo Concurrency::parallel_for_each. Cada llamada a parallel_for_each emplea una técnica diferente para calcular el cuadrado de cada elemento de un objeto std::array.

// comparing-work-functions.cpp
// compile with: /EHsc
#include <ppl.h>
#include <array>
#include <iostream>

using namespace Concurrency;
using namespace std;

// Function object (functor) class that computes the square of its input.
template<class Ty>
class SquareFunctor
{
public:
   void operator()(Ty& n) const
   {
      n *= n;
   }
};

// Function that computes the square of its input.
template<class Ty>
void square_function(Ty& n)
{
   n *= n;
}

int wmain()
{
   // Create an array object that contains 5 values.
   array<int, 5> values = { 1, 2, 3, 4, 5 };

   // Use a lambda function, a function object, and a function pointer to 
   // compute the square of each element of the array in parallel.

   // Use a lambda function to square each element.
   parallel_for_each(values.begin(), values.end(), [](int& n){n *= n;});

   // Use a function object (functor) to square each element.
   parallel_for_each(values.begin(), values.end(), SquareFunctor<int>());

   // Use a function pointer to square each element.
   parallel_for_each(values.begin(), values.end(), &square_function<int>);

   // Print each element of the array to the console.
   for_each(values.begin(), values.end(), [](int& n) { 
      wcout << n << endl;
   });
}

Este ejemplo produce el siguiente resultado.

1
256
6561
65536
390625

Para obtener más información acerca de las funciones lambda en C++, vea Lambda Expressions in C++.

[Ir al principio]

Requisitos

En la siguiente tabla se muestran los archivos de encabezado asociados a cada componente del Runtime de simultaneidad:

Componente

Archivos de encabezado

Parallel Patterns Library (PPL)

ppl.h

concurrent_queue.h

concurrent_vector.h

Biblioteca de agentes asincrónicos

agents.h

Programador de tareas

concrt.h

Administrador de recursos

concrtrm.h

El Runtime de simultaneidad se declara en el espacio de nombres Concurrency. El espacio de nombres Concurrency::details es compatible con el marco del Runtime de simultaneidad y no está diseñado para usarse directamente en el código.

El Runtime de simultaneidad se proporciona como parte de la Biblioteca en tiempo de ejecución de C (CRT). Para obtener más información sobre cómo compilar una aplicación que utiliza CRT, vea C Run-Time Libraries.

[Ir al principio]

Historial de cambios

Fecha

Historial

Motivo

Julio de 2010

Contenido reorganizado.

Mejora de la información.