Cómo: utilizar AsyncPackage para cargar VSPackages en segundo planoHow to: Use AsyncPackage to Load VSPackages in the Background

Cargar e inicializar un paquete de VS pueden dar lugar a E/S de disco.Loading and initializing a VS package can result in disk I/O. Si este tipo E/S ocurre en el subproceso de interfaz de usuario, puede provocar problemas de capacidad de respuesta.If such I/O happens on the UI thread, it can lead to responsiveness issues. Para solucionar este problema, Visual Studio 2015 introdujo la AsyncPackage clase que permite la carga del paquete en un subproceso en segundo plano.To address this, Visual Studio 2015 introduced the AsyncPackage class that enables package loading on a background thread.

Crear un AsyncPackageCreating an AsyncPackage

Puede empezar a crear un proyecto VSIX (archivo > Nuevo > proyecto > Visual C# > extensibilidad > proyecto VSIX) y la adición de un paquete VSPackage al proyecto (haga clic con el botón secundario en el proyecto y Agregar/nuevo elemento / elemento de C# / Paquete de Extensibility/Visual Studio).You can start by creating a VSIX project (File > New > Project > Visual C# > Extensibility > VSIX Project) and adding a VSPackage to the project (right click on the project and Add/New Item/C# item/Extensibility/Visual Studio Package). A continuación, puede crear sus servicios y agregar esos servicios al paquete.You can then create your services and add those services to your package.

  1. Derivar el paquete desde AsyncPackage.Derive the package from AsyncPackage.

  2. Si va a proporcionar servicios cuya consulta puede provocar el paquete de carga:If you are providing services whose querying may cause your package to load:

    Para indicar a Visual Studio que el paquete es seguro para la carga en segundo plano y no formen parte de este comportamiento, el PackageRegistrationAttribute debe establecer AllowsBackgroundLoading propiedad en true en el constructor de atributo.To indicate to Visual Studio that your package is safe for background loading and to opt into this behavior, your PackageRegistrationAttribute should set AllowsBackgroundLoading property to true in the attribute constructor.

    [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]  
    

    Para indicar a Visual Studio que es seguro crear una instancia del servicio en un subproceso en segundo plano, debe establecer el IsAsyncQueryable propiedad en true en el ProvideServiceAttribute constructor.To indicate to Visual Studio that it is safe to instantiate your service on a background thread, you should set the IsAsyncQueryable property to true in the ProvideServiceAttribute constructor.

    [ProvideService(typeof(SMyTestService), IsAsyncQueryable = true)]  
    
  3. Si va a cargar a través de contextos de la interfaz de usuario, debe especificar PackageAutoLoadFlags.BackgroundLoad para el ProvideAutoLoadAttribute o el valor (0 x 2) en los indicadores se escribe como el valor de entrada de carga automática de su paquete.If you are loading via UI contexts, then you should specify PackageAutoLoadFlags.BackgroundLoad for the ProvideAutoLoadAttribute OR the value (0x2) into the flags written as the value of your package's auto-load entry.

    [ProvideAutoLoad(UIContextGuid, PackageAutoLoadFlags.BackgroundLoad)]  
    
  4. Si tiene trabajo inicialización asincrónica, se debe invalidar InitializeAsync.If you have asynchronous initialization work to do, you should override InitializeAsync. Quitar el Initialize() método proporcionada la plantilla VSIX.Remove the Initialize() method provided by the VSIX template. (El Initialize() método AsyncPackage está sellado).(The Initialize() method in AsyncPackage is sealed). Puede usar cualquiera de los <xref:Microsoft.VisualStudio.Shell.AsyncPackage.AddService%2A> métodos para agregar servicios asincrónicos al paquete.You can use any of the <xref:Microsoft.VisualStudio.Shell.AsyncPackage.AddService%2A> methods to add asynchronous services to your package.

    Nota: Para llamar a base. InitializeAsync(), puede cambiar el código fuente para:NOTE: To call base.InitializeAsync(), you can change your source code to:

    await base.InitializeAsync(cancellationToken, progress);  
    
  5. Debe tener cuidado para no hacer RPC (llamada a procedimiento remoto) desde el código de inicialización asincrónica (en InitializeAsync).You must take care to NOT make RPCs (Remote Procedure Call) from your asynchronous initialization code (in InitializeAsync). Estos pueden producirse cuando se llama a GetService directa o indirectamente.These can occur when you call GetService directly or indirectly. Cuando se requieren las cargas de sincronización, el subproceso de interfaz de usuario se bloqueará con JoinableTaskFactory.When sync loads are required, the UI thread will block using JoinableTaskFactory. El modelo bloqueo predeterminado deshabilita RPC.The default blocking model disables RPCs. Esto significa que si intenta usar una llamada RPC de sus tareas asincrónicas, interbloquee si el subproceso de interfaz de usuario es esperando el paquete que desea cargar.This means that if you attempt to use an RPC from your async tasks, you will deadlock if the UI thread is itself waiting for your package to load. La alternativa general es calcular las referencias de código para el subproceso de interfaz de usuario si es necesario usar algo parecido a generador de tareas que se puede unirdel SwitchToMainThreadAsync o algún otro mecanismo que no usa una RPC.The general alternative is to marshal your code to the UI thread if needed using something like Joinable Task Factory's SwitchToMainThreadAsync or some other mechanism that does not use an RPC. No utilice ThreadHelper.Generic.Invoke o generalmente bloquear el subproceso que realiza la llamada espera obtener al subproceso de interfaz de usuario.Do NOT use ThreadHelper.Generic.Invoke or generally block the calling thread waiting to get to the UI thread.

    Nota: Debe evitar el uso GetService o QueryService en su InitializeAsync método.NOTE: You should avoid using GetService or QueryService in your InitializeAsync method. Si tiene que utilizarlos, debe cambiar al subproceso de interfaz de usuario en primer lugar.If you have to use those, you will need to switch to the UI thread first. La alternativa es usar <xref:Microsoft.VisualStudio.Shell.AsyncServiceProvider.GetServiceAsync%2A> desde su AsyncPackage (convirtiéndolo a IAsyncServiceProvider.)The alternative is to use <xref:Microsoft.VisualStudio.Shell.AsyncServiceProvider.GetServiceAsync%2A> from your AsyncPackage (by casting it to IAsyncServiceProvider.)

    C#: Cree una AsyncPackage:C#: Create an AsyncPackage :

[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]       
[ProvideService(typeof(SMyTestService), IsAsyncQueryable = true)]   
public sealed class TestPackage : AsyncPackage   
{   
    protected override Task InitializeAsync(System.Threading.CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)   
    {               
        this.AddService(typeof(SMyTestService), CreateService, true);   
        return Task.FromResult<object>(null);   
    }   
}  

Convertir un VSPackage existente en AsyncPackageConvert an existing VSPackage to AsyncPackage

La mayoría del trabajo es lo mismo que crear un nuevo AsyncPackage.The majority of the work is the same as creating a new AsyncPackage. Debe seguir los pasos del 1 al 5 anterior.You need to follow steps 1 through 5 above. También debe tomar las precauciones adicionales en lo siguiente:You also need to take extra caution on the following:

  1. No olvide quitar la inicializar invalidación que tenía en el paquete.Remember to remove the Initialize override you had in your package.

  2. Evitar los interbloqueos: pueden producirse errores ocultos RPC en el código que realizará ahora de un subproceso en segundo plano.Avoid deadlocks: There could be hidden RPCs in your code which now happen on a background thread. Debe asegurarse de que si va a realizar una llamada RPC (p. ej. GetService), es necesario (1) cambia para el subproceso principal o (2) use la versión asincrónica de la API si existe (por ejemplo, GetServiceAsync).You need to ensure that if you are making an RPC (e.g. GetService), you need to either (1) switch to the main thread or (2) use the asynchronous version of the API if one exists (e.g. GetServiceAsync).

  3. No cambie entre los subprocesos con demasiada frecuencia.Do not switch between threads too frequently. Intenta localizar el trabajo que puede suceder en un subproceso en segundo plano.Try to localize the work that can happen in a background thread. Esto reduce el tiempo de carga.This reduces the load time.

Enviando consulta a servicios de AsyncPackageQuerying Services from AsyncPackage

Un AsyncPackage puede o no puede cargar de forma asincrónica según el llamador.An AsyncPackage may or may not load asynchronously depending on the caller. Por ejemplo,For instance,

  • Si el llamador llama GetService o QueryService (ambas API sincrónico) oIf the caller called GetService or QueryService (both synchronous APIs) or

  • Si el llamador llama IVsShell::LoadPackage (o IVsShell5::LoadPackageWithContext) oIf the caller called IVsShell::LoadPackage (or IVsShell5::LoadPackageWithContext) or

  • La carga se desencadena en un contexto de la interfaz de usuario, pero no especificó que el mecanismo de contexto de la interfaz de usuario puede cargar asincrónicamenteThe load is triggered by a UI context, but you did not specify the UI context mechanism can load you asynchronously

    a continuación, el paquete se cargará sincrónicamente.then your package will load synchronously.

    Tenga en cuenta que el paquete todavía tiene una oportunidad (en su fase de inicialización asincrónica) para que funcione el subproceso de interfaz de usuario, aunque se bloqueará el subproceso de interfaz de usuario para la finalización de ese trabajo.Note that your package still has an opportunity (in its asynchronous initialization phase) to do work off the UI thread, though the UI thread will be blocked for that work's completion. Si el llamador usa IAsyncServiceProvider asincrónicamente la consulta para el servicio, a continuación, la carga e inicialización hará asincrónicamente suponiendo que no bloqueen inmediatamente en el objeto de tarea resultante.If the caller uses IAsyncServiceProvider to asynchronously query for your service, then your load and initialization will be done asynchronously assuming they don't immediately block on the resulting task object.

    C#: Cómo consultar el servicio de forma asincrónica:C#: How to query service asynchronously:

using Microsoft.VisualStudio.Shell;   
using Microsoft.VisualStudio.Shell.Interop;   

IAsyncServiceProvider asyncServiceProvider = Package.GetService(typeof(SAsyncServiceProvider)) as IAsyncServiceProvider;   
IMyTestService testService = await ayncServiceProvider.GetServiceAsync(typeof(SMyTestService)) as IMyTestService;