¿Le resultó útil esta página?
Sus comentarios sobre este contenido son muy importantes. Háganos saber su opinión.
¿Tiene comentarios adicionales?
Caracteres restantes: 1500
Exportar (0) Imprimir
Expandir todo
Este artículo se tradujo de forma manual. Mueva el puntero sobre las frases del artículo para ver el texto original. Más información.
Traducción
Original

Grupo de subprocesos administrados

La clase ThreadPool proporciona a la aplicación un grupo de subprocesos de trabajo administrados por el sistema, que le permite concentrarse en las tareas de la aplicación en lugar de en la administración de los subprocesos. Si tiene tareas cortas que requieran procesamiento en segundo plano, el grupo de subprocesos administrados permite aprovechar fácilmente las ventajas de varios subprocesos. Por ejemplo, a partir de .NET Framework 4, puede crear objetos Task y Task(Of TResult), que realizan tareas asincrónicas en los subprocesos del grupo de subprocesos.

Nota Nota

A partir de .NET Framework 2.0 Service Pack 1, mejora considerablemente el rendimiento del grupo de subprocesos en tres áreas clave que se identificaron como cuellos de botella en las versiones anteriores de .NET Framework: poner tareas en cola, enviar subprocesos del grupo de subprocesos y enviar subprocesos de finalización de E/S. Para utilizar esta funcionalidad, la aplicación debe utilizar .NET Framework 3,5 o posterior como destino.

Para las tareas en segundo plano que interactúan con la interfaz de usuario, la versión 2.0 de .NET Framework también proporciona la clase BackgroundWorker, que se comunica mediante eventos generados en el subproceso de la interfaz de usuario.

.NET Framework utiliza los subprocesos del grupo de subprocesos para muchos fines, incluida la finalización de E/S asincrónica, las devoluciones de llamada del temporizador, las operaciones de espera registradas, las llamadas de métodos asincrónicos mediante delegados y las conexiones de socket System.Net.

Hay varios escenarios en los que es adecuado crear y administrar sus propios subprocesos en lugar de utilizar subprocesos del grupo de subprocesos:

  • Necesita un subproceso en primer plano.

  • Necesita que un subproceso tenga una prioridad determinada.

  • Tiene tareas que hacen que el subproceso se bloquee durante largos períodos de tiempo. El grupo de subprocesos tiene un número máximo de subprocesos, por lo que si hay un gran número de subprocesos del grupo de subprocesos bloqueados, esto puede impedir que se inicien las tareas.

  • Debe colocar los subprocesos en un contenedor uniproceso. Todos los subprocesos ThreadPool están en el contenedor multiproceso.

  • Debe tener una identidad estable asociada al subproceso o dedicar un subproceso a una tarea.

Los subprocesos del grupo de subprocesos son subprocesos en segundo plano. Consulte Subprocesos de primer y segundo plano- Cada subproceso utiliza el tamaño de pila predeterminado, se ejecuta con la prioridad predeterminada y está en el contenedor multiproceso.

Hay solo un grupo de subprocesos por cada proceso.

0ka9477y.collapse_all(es-es,VS.110).gifExcepciones en los subprocesos del grupo de subprocesos

Las excepciones no controladas en los subprocesos del grupo de subprocesos finalizan el proceso. Hay tres excepciones de esta regla:

  • Se genera un ThreadAbortException en un subproceso del grupo de subprocesos, porque se llamó a Abort.

  • Se genera un AppDomainUnloadedException en un subproceso del grupo de subprocesos, porque se está descargando el dominio de aplicación.

  • Common Language Runtime o un proceso de host finaliza el subproceso.

Para más información, consulte Excepciones en subprocesos administrados.

Nota Nota

En las versiones 1.0 y 1.1 de .NET Framework, Common Language Runtime intercepta silenciosamente las excepciones no controladas en los subprocesos del grupo de subprocesos. Esto puede dañar el estado de la aplicación y puede acabar haciendo que las aplicaciones no respondan, lo cual puede ser muy difícil de depurar.

0ka9477y.collapse_all(es-es,VS.110).gifNúmero máximo de subprocesos del grupo de subprocesos

El número de operaciones que pueden ponerse en la cola del grupo de subprocesos está limitado solamente por la memoria disponible. Sin embargo, el grupo de subprocesos limita el número de subprocesos que pueden estar activos en el proceso de forma simultánea. A partir de .NET Framework 4, el tamaño predeterminado del grupo de subprocesos de un proceso depende de varios factores, como el tamaño del espacio de direcciones virtuales. Un proceso puede llamar al método GetMaxThreads para determinar el número de subprocesos.

El número máximo de subprocesos se puede controlar con los métodos GetMaxThreads y SetMaxThreads.

Nota Nota

En las versiones 1.0 y 1.1 de .NET Framework, el tamaño del grupo de subprocesos no se puede establecer desde el código administrado. El código que hospeda Common Language Runtime puede establecer el tamaño con CorSetMaxThreads, definido en mscoree.h.

0ka9477y.collapse_all(es-es,VS.110).gifMínimos del grupo de subprocesos

El grupo de subprocesos ofrece nuevos subprocesos de trabajo o subprocesos de finalización de E/S a petición hasta que llega a un mínimo especificado para cada categoría. Puede utilizar el método GetMinThreads para obtener estos valores mínimos.

Nota Nota

Cuando la demanda es baja, el número real de subprocesos del grupo de subprocesos puede descender por debajo de los valores mínimos.

Cuando se alcanza el mínimo, el grupo de subprocesos puede crear subprocesos adicionales o esperar hasta que se completen algunas tareas. A partir de .NET Framework 4, el grupo de subprocesos crea y destruye subprocesos de trabajo para optimizar el rendimiento, definido como el número de tareas que se completan por unidad de tiempo. Si hay demasiados pocos subprocesos, puede que los recursos disponibles no se usen de manera óptima, mientras que si hay demasiados subprocesos, puede aumentar la contención de recursos.

Nota de precaución Precaución

Puede utilizar el método SetMinThreads para aumentar el número mínimo de subprocesos inactivos. Sin embargo, aumentar innecesariamente estos valores puede causar problemas de rendimiento. Si se inician demasiadas tareas al mismo tiempo, puede que todas ellas parezcan funcionar con lentitud. En la mayoría de los casos, el grupo de subprocesos funciona mejor con su propio algoritmo de asignación de subprocesos.

El grupo de subprocesos también proporciona los métodos ThreadPool.UnsafeQueueUserWorkItem y ThreadPool.UnsafeRegisterWaitForSingleObject. Utilice estos métodos solamente cuando tenga la seguridad de que la pila del llamador es irrelevante para las comprobaciones de seguridad que se realizan durante la ejecución de la tarea en cola. QueueUserWorkItem y RegisterWaitForSingleObject capturan la pila del llamador, que se combina en la pila del subproceso del grupo de subprocesos cuando el subproceso empieza a ejecutar una tarea. Si es necesaria una comprobación de seguridad, debe comprobarse toda la pila. La comprobación proporciona seguridad, pero también supone un coste para el rendimiento.

A partir de .NET Framework 4, la manera más fácil de usar el grupo de subprocesos es utilizar la Biblioteca de procesamiento paralelo basado en tareas (TPL). De forma predeterminada, los tipos de biblioteca de procesamiento paralelo, como Task y Task(Of TResult), utilizan subprocesos del grupo de subprocesos para ejecutar tareas. También puede utilizar el grupo de subprocesos llamando a ThreadPool.QueueUserWorkItem desde código administrado (o CorQueueUserWorkItem desde código no administrado) y pasando un delegado WaitCallback que represente al método que realiza la tarea. Otra forma de usar el grupo de subprocesos es poner en cola los elementos de trabajo que están relacionados con una operación de espera mediante el método ThreadPool.RegisterWaitForSingleObject y pasar un WaitHandle que, cuando se señala o cuando se agota el tiempo de espera, llame al método representado por el delegado WaitOrTimerCallback. Los subprocesos del grupo de subprocesos se usan para invocar métodos de devolución de llamada.

Los ejemplos de código de esta sección muestran el grupo de subprocesos con la clase Task, el método ThreadPool.QueueUserWorkItem y el método ThreadPool.RegisterWaitForSingleObject.

0ka9477y.collapse_all(es-es,VS.110).gifEjecutar tareas asincrónicas con la biblioteca TPL

En el siguiente ejemplo, se muestra cómo crear y usar un objeto Task para llamar al método TaskFactory.StartNew. Para ver un ejemplo que utiliza la clase Task(Of TResult) con el fin de devolver un valor de una tarea asincrónica, consulte Cómo: Devolver un valor de una tarea.


Imports System.Threading
Imports System.Threading.Tasks

Module Example
    Public Sub Main()
        Dim action As Action(Of Object) = 
              Sub(obj As Object)
                 Console.WriteLine("Task={0}, obj={1}, Thread={2}", 
                 Task.CurrentId, obj,
                 Thread.CurrentThread.ManagedThreadId)
              End Sub

        ' Construct an unstarted task
        Dim t1 As New Task(action, "alpha")

        ' Construct a started task
        Dim t2 As Task = Task.Factory.StartNew(action, "beta")
        ' Block the main thread to demonstate that t2 is executing
        t2.Wait()

        ' Launch t1 
        t1.Start()
        Console.WriteLine("t1 has been launched. (Main Thread={0})",
                          Thread.CurrentThread.ManagedThreadId)
        ' Wait for the task to finish.
        t1.Wait()

        ' Construct a started task using Task.Run.
        Dim taskData As String = "delta"
        Dim t3 As Task = Task.Run(Sub()
                                     Console.WriteLine("Task={0}, obj={1}, Thread={2}",
                                     Task.CurrentId, taskData,
                                     Thread.CurrentThread.ManagedThreadId)
                                  End Sub)
        ' Wait for the task to finish.
        t3.Wait()

        ' Construct an unstarted task
        Dim t4 As New Task(action, "gamma")
        ' Run it synchronously
        t4.RunSynchronously()
        ' Although the task was run synchronously, it is a good practice
        ' to wait for it in the event exceptions were thrown by the task.
        t4.Wait()
    End Sub
End Module
' The example displays output like the following:
'       Task=1, obj=beta, Thread=3
'       t1 has been launched. (Main Thread=1)
'       Task=2, obj=alpha, Thread=3
'       Task=3, obj=delta, Thread=3
'       Task=4, obj=gamma, Thread=1


0ka9477y.collapse_all(es-es,VS.110).gifEjecutar código de forma asincrónica con QueueUserWorkItem

En el ejemplo siguiente, se pone en cola una tarea muy sencilla, representada por el método ThreadProc, con el método QueueUserWorkItem.


Imports System
Imports System.Threading

Public Class Example
    Public Shared Sub Main()
        ' Queue the task.
        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ThreadProc))

        Console.WriteLine("Main thread does some work, then sleeps.")
        ' If you comment out the Sleep, the main thread exits before
        ' the thread pool task runs.  The thread pool uses background
        ' threads, which do not keep the application running.  (This
        ' is a simple example of a race condition.)
        Thread.Sleep(1000)

        Console.WriteLine("Main thread exits.")
    End Sub

    ' This thread procedure performs the task.
    Shared Sub ThreadProc(stateInfo As Object)
        ' No state object was passed to QueueUserWorkItem, so
        ' stateInfo is null.
        Console.WriteLine("Hello from the thread pool.")
    End Sub
End Class


0ka9477y.collapse_all(es-es,VS.110).gifProporcionar datos de tareas para QueueUserWorkItem

El siguiente ejemplo de código utiliza el método QueueUserWorkItem para poner en cola una tarea y proporcionar los datos de la tarea.


Imports System
Imports System.Threading

' TaskInfo holds state information for a task that will be
' executed by a ThreadPool thread.
Public class TaskInfo
    ' State information for the task.  These members
    ' can be implemented as read-only properties, read/write
    ' properties with validation, and so on, as required.
    Public Boilerplate As String
    Public Value As Integer

    ' Public constructor provides an easy way to supply all
    ' the information needed for the task.
    Public Sub New(text As String, number As Integer)
        Boilerplate = text
        Value = number
    End Sub
End Class

Public Class Example
    Public Shared Sub Main()
        ' Create an object containing the information needed
        ' for the task.
        Dim ti As New TaskInfo("This report displays the number {0}.", 42)

        ' Queue the task and data.
        If ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ThreadProc), ti) Then
            Console.WriteLine("Main thread does some work, then sleeps.")

            ' If you comment out the Sleep, the main thread exits before
            ' the ThreadPool task has a chance to run.  ThreadPool uses
            ' background threads, which do not keep the application
            ' running.  (This is a simple example of a race condition.)
            Thread.Sleep(1000)

            Console.WriteLine("Main thread exits.")
        Else
            Console.WriteLine("Unable to queue ThreadPool request.")
        End If
    End Sub

    ' The thread procedure performs the independent task, in this case
    ' formatting and printing a very simple report.
    '
    Shared Sub ThreadProc(stateInfo As Object)
        Dim ti As TaskInfo = CType(stateInfo, TaskInfo)
        Console.WriteLine(ti.Boilerplate, ti.Value)
    End Sub
End Class


0ka9477y.collapse_all(es-es,VS.110).gifUso de RegisterWaitForSingleObject

En el ejemplo siguiente se muestran diversas características de subprocesamiento:


Imports System
Imports System.Threading

' TaskInfo contains data that will be passed to the callback
' method.
Public Class TaskInfo
    public Handle As RegisteredWaitHandle = Nothing
    public OtherInfo As String = "default"
End Class

Public Class Example
    Public Shared Sub Main()
        ' The main thread uses AutoResetEvent to signal the
        ' registered wait handle, which executes the callback
        ' method.
        Dim ev As New AutoResetEvent(false)

        Dim ti As New TaskInfo()
        ti.OtherInfo = "First task"
        ' The TaskInfo for the task includes the registered wait
        ' handle returned by RegisterWaitForSingleObject.  This
        ' allows the wait to be terminated when the object has
        ' been signaled once (see WaitProc).
        ti.Handle = ThreadPool.RegisterWaitForSingleObject( _
            ev, _
            New WaitOrTimerCallback(AddressOf WaitProc), _
            ti, _
            1000, _
            false _
        )

        ' The main thread waits about three seconds, to demonstrate 
        ' the time-outs on the queued task, and then signals.
        Thread.Sleep(3100)
        Console.WriteLine("Main thread signals.")
        ev.Set()

        ' The main thread sleeps, which should give the callback
        ' method time to execute.  If you comment out this line, the
        ' program usually ends before the ThreadPool thread can execute.
        Thread.Sleep(1000)
        ' If you start a thread yourself, you can wait for it to end
        ' by calling Thread.Join.  This option is not available with 
        ' thread pool threads.
    End Sub

    ' The callback method executes when the registered wait times out,
    ' or when the WaitHandle (in this case AutoResetEvent) is signaled.
    ' WaitProc unregisters the WaitHandle the first time the event is 
    ' signaled.
    Public Shared Sub WaitProc(state As Object, timedOut As Boolean)
        ' The state object must be cast to the correct type, because the
        ' signature of the WaitOrTimerCallback delegate specifies type
        ' Object.
        Dim ti As TaskInfo = CType(state, TaskInfo)

        Dim cause As String = "TIMED OUT"
        If Not timedOut Then
            cause = "SIGNALED"
            ' If the callback method executes because the WaitHandle is
            ' signaled, stop future execution of the callback method
            ' by unregistering the WaitHandle.
            If Not ti.Handle Is Nothing Then
                ti.Handle.Unregister(Nothing)
            End If
        End If 

        Console.WriteLine("WaitProc( {0} ) executes on thread {1}; cause = {2}.", _
            ti.OtherInfo, _
            Thread.CurrentThread.GetHashCode().ToString(), _
            cause _
        )
    End Sub
End Class


Adiciones de comunidad

AGREGAR
Mostrar:
© 2015 Microsoft