Condividi tramite


Utilizzo della funzionalità Async per l'accesso ai file (C# e Visual Basic)

È possibile utilizzare la funzionalità Asincrona per accedere ai file. Tramite la funzionalità async, è possibile chiamare i metodi asincroni senza utilizzare i callback o dividere il codice tramite i metodi o più espressioni lambda. Per rendere il codice sincrono asincrono, appena si chiama un metodo asincrono anziché un metodo sincrono e aggiungere alcune parole chiave al codice.

È opportuno considerare i seguenti motivi per l'aggiunta asynchrony le chiamate di accesso al file:

  • Asynchrony rende le applicazioni con interfaccia utente più reattive poiché il thread UI che avvia l'operazione può eseguire altro lavoro. Se il thread UI deve eseguire codice che richiede molto tempo, ad esempio più di 50 millisecondi), l'interfaccia utente può bloccarsi fino a I/O non sia completo e il thread UI possa elaborare nuovamente la tastiera e l'input del mouse e altri eventi.

  • Asynchrony migliorare la scalabilità di ASP.NET e altre applicazioni basate su server riducendo così la necessità di thread. Se l'applicazione utilizza un thread dedicato per risposta e mille richieste vengono gestite contemporaneamente, di milli thread sono necessarie. Le operazioni asincrone non devono spesso utilizzare un thread durante l'attesa. Utilizzano il thread di completamento di I/O esistente brevemente alla fine.

  • Latenza di un'operazione di accesso ai file potrebbe essere condizioni correnti di seguito molto bassa, ma la latenza può aumentare notevolmente in futuro. Ad esempio, è stato spostato in un server in cui è tramite il mondo.

  • Un ulteriore sovraccarico della funzionalità di Async è piccolo.

  • Le attività asincrone possono essere eseguite in parallelo.

Eseguire gli esempi

Nota

Gli esempi di questo argomento non applicano a Windows Store le applicazioni, che sono applicazioni Windows 8 che sono schermo intero e adatta per l'interazione tocco.Per informazioni su come utilizzare l'accesso ai file async nelle applicazioni Windows Store, vedere Panoramica di .NET per le app di Windows Store e I/O di file e di flussi.Per esempi di I/O di file per le applicazioni Windows Store, è possibile scaricare Esempio di accesso ai file.

Per eseguire gli esempi di questo argomento, è possibile creare Applicazione WPF o Applicazione Windows Form quindi aggiungere Pulsante. Nell'evento Click del pulsante, aggiungere una chiamata al metodo in ogni esempio.

Negli esempi seguenti, includere seguente Imports (Visual Basic) o istruzioni using (C#).

Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.IO
Imports System.Text
Imports System.Threading.Tasks
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;

Utilizzo della classe di FILESTREAM

Gli esempi di questo argomento utilizzano la classe FileStream, che include un'opzione che consente l'i/o asincrono di verificare il livello del sistema operativo. Utilizzando questa opzione, è possibile evitare di bloccare un thread threadpool in molti casi. Per abilitare questa opzione, specificare l'argomento options=FileOptions.Asynchronous o useAsync=true nella chiamata del costruttore.

Non è possibile utilizzare questa opzione con StreamReader e StreamWriter se si apre direttamente specificando un percorso di file. Tuttavia, è possibile utilizzare questa opzione se si assegna loro Stream che la classe FileStream ha aperto. Si noti che le chiamate asincrone sono più veloci nelle applicazioni di interfaccia utente anche se un thread è bloccato threadpool, poiché il thread UI non viene bloccato durante l'attesa.

Scrittura di testo

L'esempio seguente scrive il testo in un file. A ogni attendere l'istruzione, le il metodo immediatamente. Quando I/O di file è completo, il metodo riprende all'istruzione che segue l'istruzione di attesa. Si noti che il modificatore async della definizione di metodi che utilizzano l'istruzione di attesa.

Public Async Sub ProcessWrite()
    Dim filePath = "temp2.txt" 
    Dim text = "Hello World" & ControlChars.CrLf

    Await WriteTextAsync(filePath, text)
End Sub 

Private Async Function WriteTextAsync(filePath As String, text As String) As Task
    Dim encodedText As Byte() = Encoding.Unicode.GetBytes(text)

    Using sourceStream As New FileStream(filePath,
        FileMode.Append, FileAccess.Write, FileShare.None,
        bufferSize:=4096, useAsync:=True)

        Await sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
    End Using 
End Function
public async void ProcessWrite()
{
    string filePath = @"temp2.txt";
    string text = "Hello World\r\n";

    await WriteTextAsync(filePath, text);
}

private async Task WriteTextAsync(string filePath, string text)
{
    byte[] encodedText = Encoding.Unicode.GetBytes(text);

    using (FileStream sourceStream = new FileStream(filePath,
        FileMode.Append, FileAccess.Write, FileShare.None,
        bufferSize: 4096, useAsync: true))
    {
        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    };
}

Nell'esempio originale sarà presente l'istruzione await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);, una contrazione di due seguenti istruzioni:

Dim theTask As Task = sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
Await theTask
Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
await theTask;

La prima istruzione restituisce un'attività e causa del file a partire. La seconda istruzione all'attesa comporta il metodo immediatamente alla chiusura e restituire un'attività diverso. Quando del file successivamente completa, termine dell'istruzione successiva all'attesa. Per ulteriori informazioni, vedere Flusso di controllo in programmi asincroni (C# e Visual Basic) e Procedura dettagliata: utilizzo del debugger con metodi Async.

Lettura del testo

Nell'esempio riportato di seguito si legge del testo da un file. Il testo viene memorizzato nel buffer e, in questo caso, viene posizionato in StringBuilder. A differenza dell'esempio precedente, la valutazione dell'attesa produce un valore. Il metodo ReadAsync restituisce Task<Int32>, pertanto la valutazione dell'attesa produce un valore Int32 (numRead) dopo l'operazione completa. Per ulteriori informazioni, vedere Tipi restituiti asincroni (C# e Visual Basic).

Public Async Sub ProcessRead()
    Dim filePath = "temp2.txt" 

    If File.Exists(filePath) = False Then
        Debug.WriteLine("file not found: " & filePath)
    Else 
        Try 
            Dim text As String = Await ReadTextAsync(filePath)
            Debug.WriteLine(text)
        Catch ex As Exception
            Debug.WriteLine(ex.Message)
        End Try 
    End If 
End Sub 

Private Async Function ReadTextAsync(filePath As String) As Task(Of String)

    Using sourceStream As New FileStream(filePath,
        FileMode.Open, FileAccess.Read, FileShare.Read,
        bufferSize:=4096, useAsync:=True)

        Dim sb As New StringBuilder

        Dim buffer As Byte() = New Byte(&H1000) {}
        Dim numRead As Integer
        numRead = Await sourceStream.ReadAsync(buffer, 0, buffer.Length)
        While numRead <> 0
            Dim text As String = Encoding.Unicode.GetString(buffer, 0, numRead)
            sb.Append(text)

            numRead = Await sourceStream.ReadAsync(buffer, 0, buffer.Length)
        End While 

        Return sb.ToString
    End Using 
End Function
public async void ProcessRead()
{
    string filePath = @"temp2.txt";

    if (File.Exists(filePath) == false)
    {
        Debug.WriteLine("file not found: " + filePath);
    }
    else
    {
        try
        {
            string text = await ReadTextAsync(filePath);
            Debug.WriteLine(text);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }
}

private async Task<string> ReadTextAsync(string filePath)
{
    using (FileStream sourceStream = new FileStream(filePath,
        FileMode.Open, FileAccess.Read, FileShare.Read,
        bufferSize: 4096, useAsync: true))
    {
        StringBuilder sb = new StringBuilder();

        byte[] buffer = new byte[0x1000];
        int numRead;
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
            sb.Append(text);
        }

        return sb.ToString();
    }
}

L'I/O asincrono parallelo

Nell'esempio seguente viene illustrata l'elaborazione parallela scrivendo 10 file di testo. Per ogni file, il metodo WriteAsync restituisce un'attività che viene quindi aggiunto a un elenco delle attività. L'istruzione await Task.WhenAll(tasks); esce dal metodo e ripresa nel metodo quando del file è completo per tutte le attività.

L'esempio chiudere tutte le istanze FileStream in un blocco finally dopo che le attività vengono completate. Se ogni FileStream invece è stato creato in un'istruzione using, FileStream potrebbe essere eliminato prima che l'attività è stata completata.

Si noti che qualsiasi incremento delle prestazioni è quasi completamenteelaborazione in parallelo e non dall'elaborazione asincrona. I vantaggi di asynchrony sono che non lega i thread e che non lega il thread di interfaccia utente.

Public Async Sub ProcessWriteMult()
    Dim folder = "tempfolder\" 
    Dim tasks As New List(Of Task)
    Dim sourceStreams As New List(Of FileStream)

    Try 
        For index = 1 To 10
            Dim text = "In file " & index.ToString & ControlChars.CrLf

            Dim fileName = "thefile" & index.ToString("00") & ".txt" 
            Dim filePath = folder & fileName

            Dim encodedText As Byte() = Encoding.Unicode.GetBytes(text)

            Dim sourceStream As New FileStream(filePath,
                FileMode.Append, FileAccess.Write, FileShare.None,
                bufferSize:=4096, useAsync:=True)

            Dim theTask As Task = sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
            sourceStreams.Add(sourceStream)

            tasks.Add(theTask)
        Next

        Await Task.WhenAll(tasks)
    Finally 
        For Each sourceStream As FileStream In sourceStreams
            sourceStream.Close()
        Next 
    End Try 
End Sub
public async void ProcessWriteMult()
{
    string folder = @"tempfolder\";
    List<Task> tasks = new List<Task>();
    List<FileStream> sourceStreams = new List<FileStream>();

    try
    {
        for (int index = 1; index <= 10; index++)
        {
            string text = "In file " + index.ToString() + "\r\n";

            string fileName = "thefile" + index.ToString("00") + ".txt";
            string filePath = folder + fileName;

            byte[] encodedText = Encoding.Unicode.GetBytes(text);

            FileStream sourceStream = new FileStream(filePath,
                FileMode.Append, FileAccess.Write, FileShare.None,
                bufferSize: 4096, useAsync: true);

            Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
            sourceStreams.Add(sourceStream);

            tasks.Add(theTask);
        }

        await Task.WhenAll(tasks);
    }

    finally
    {
        foreach (FileStream sourceStream in sourceStreams)
        {
            sourceStream.Close();
        }
    }
}

In utilizzando i metodi ReadAsync e WriteAsync, è possibile specificare CancellationToken, che è possibile utilizzare per annullare il centro flusso di un'operazione. Per ulteriori informazioni, vedere Ottimizzazione dell'applicazione Async (C# e Visual Basic) e Annullamento in thread gestiti.

Vedere anche

Attività

Procedura dettagliata: utilizzo del debugger con metodi Async

Concetti

Programmazione asincrona con Async e Await (C# e Visual Basic)

Tipi restituiti asincroni (C# e Visual Basic)

Flusso di controllo in programmi asincroni (C# e Visual Basic)