assíncrona e aguardam Passado e Presente (Actualizado)

Este artigo é conexão reproduzida:  https://www.cnblogs.com/jesse2013/p/async-and-await.htm

assíncrona e esperar aparecer depois C # 5.0, programação paralela para trazer um monte de conveniência, especialmente quando a ação no MVC também tornar-se assíncrono, iniciar um gostinho do que é assíncrona. Mas também nos dá alguns perigos ocultos programação plantadas, às vezes podemos ter alguns não sabem como produzir o Bug, especialmente se o caso não entende mesmo o segmento, mas não sabem como lidar com eles. Bem, hoje vamos dar uma boa olhada os dois irmãos e seu tio (Task) avô (Thread) e que no final o que é a diferença, este artigo será sobre Tópico a Task .NET 4.5 e depois para o assíncrono e aguardar, três para programação paralela de uma maneira geral de introdução incluem: linha aberta, a rosca retorna um resultado, a suspensão de rosca, manuseamento excepção rosca.

indexação de conteúdo

criar

 

static void Main(){

    new Thread(Go).Start();  // .NET 1.0开始就有的

    Task.Factory.StartNew(Go); // .NET 4.0 引入了 TPL

    Task.Run(new Action(Go)); // .NET 4.5 新增了一个Run的方法

}

 

public static void Go(){

    Console.WriteLine("我是另一个线程");

}

 

Deve-se notar que, depois de criar uma instância de Thread, você precisa chamar manualmente o método Start para iniciá-lo. Mas para Tarefa que, StartNew and Run, ao mesmo tempo, ambos vão criar um novo segmento, e vai começar imediatamente a ele.

segmento de pool 

  criação de threads é mais ocupada um recursos coisa, .NET fornece um pool de threads para nós para nos ajudar a criar e gerir threads. Tarefa é o padrão vai usar diretamente o pool de threads, mas thread não. Se não usar a tarefa, quer usar o pool de threads, você pode usar a classe ThreadPool.

tatic void Main() {

    Console.WriteLine("我是主线程:Thread Id {0}", Thread.CurrentThread.ManagedThreadId);

    ThreadPool.QueueUserWorkItem(Go);

 

    Console.ReadLine();

}

 

public static void Go(object data) {

    Console.WriteLine("我是另一个线程:Thread Id {0}",Thread.CurrentThread.ManagedThreadId);

}

parâmetros de entrada

static void Main() {

    new Thread(Go).Start("arg1"); // 没有匿名委托之前,我们只能这样传入一个object的参数

 

    new Thread(delegate(){  // 有了匿名委托之后...

        GoGoGo("arg1""arg2""arg3");

    });

 

    new Thread(() => {  // 当然,还有 Lambada

        GoGoGo("arg1","arg2","arg3");

    }).Start();

 

    Task.Run(() =>{  // Task能这么灵活,也是因为有了Lambda呀。

        GoGoGo("arg1""arg2""arg3");

    });

}

 

public static void Go(object name){

    // TODO

}

 

public static void GoGoGo(string arg1, string arg2, string arg3){

    // TODO

}

O valor de retorno

  Thead não retornar o valor, mas como tarefa mais avançada do curso, compõem esse recurso.

static void Main() {

    // GetDayOfThisWeek 运行在另外一个线程中

    var dayName = Task.Run<string>(() => { return GetDayOfThisWeek(); });

    Console.WriteLine("今天是:{0}",dayName.Result);

}

compartilhamento de dados

  O dito acima parâmetros e valores de retorno, nós olhamos para a questão da partilha de dados entre threads.

private static bool _isDone = false;   

static void Main(){

    new Thread(Done).Start();

    new Thread(Done).Start();

}

 

static void Done(){

    if (!_isDone) {

        _isDone = true// 第二个线程来的时候,就不会再执行了(也不是绝对的,取决于计算机的CPU数量以及当时的运行情况)

        Console.WriteLine("Done");

    }

}

Você pode compartilhar dados entre threads através da variável estática.

thread-safe

   Nós primeiro olhar para o código acima ajustes menores, eles sabem o que é thread-safe. Nós Feito abordagem duas frases para mudar sua posição.

private static bool _isDone = false;   

static void Main(){

    new Thread(Done).Start();

    new Thread(Done).Start();

    Console.ReadLine();

}

 

static void Done(){

    if (!_isDone) {

       Console.WriteLine("Done"); // 猜猜这里面会被执行几次?

        _isDone = true;

    }

}

Isso não acontece todos os acima, mas se você tiver sorte, você vai bater o jackpot. Desde o primeiro segmento ainda não teve tempo para _isDone é definido como verdadeiro, o segundo segmento entrou, mas não é o resultado que queremos, em vários segmentos, o resultado não é o resultado que esperávamos, o que não é thread-safe .

bloqueio

  Para resolver os problemas acima, vamos usar o bloqueio. O tipo de bloqueio tem bloqueio exclusivo, mutex, e leitura e escrita fechaduras, etc., estamos aqui para simplesmente mostrar-lhe o bloqueio exclusivo.

 

private static bool _isDone = false;

private static object _lock = new object();

static void Main(){

    new Thread(Done).Start();

    new Thread(Done).Start();

    Console.ReadLine();

}

 

static void Done(){

    lock (_lock){

        if (!_isDone){

            Console.WriteLine("Done"); // 猜猜这里面会被执行几次?

            _isDone = true;

        }

    }

}

Depois de adicionar outro fechamento, fechado código no mesmo tempo permitindo que apenas um acesso fio, outros segmentos serão bloqueados, e somente até que o código após o bloqueio será liberado para executar outras threads estão bloqueadas.

Semaphore Semaphore

  Eu realmente não sei como traduzir esta palavra, a partir da explicação oficial, podemos compreender. Ele pode controlar o número de threads a um pedaço de código ou um recurso acessado, depois de mais do que este montante, outros segmentos devem esperar, e por isso há agora somente após o lançamento da linha, o seguinte acesso thread pode. Este tem uma função similar com a fechadura, mas não exclusiva, ele permite que um certo número de acesso threads.

static SemaphoreSlim _sem = new SemaphoreSlim(3);    // 我们限制能同时访问的线程数量是3

static void Main(){

    for (int i = 1; i <= 5; i++) new Thread(Enter).Start(i);

    Console.ReadLine();

}

 

static void Enter(object id){

    Console.WriteLine(id + " 开始排队...");

    _sem.Wait();

    Console.WriteLine(id + " 开始执行!");         

    Thread.Sleep(1000 * (int)id);              

    Console.WriteLine(id + " 执行完毕,离开!");     

    _sem.Release();

}

No início, após os três primeiros para entrar na fila imediatamente executada, mas 4 e 5, é só esperar até depois há uma saída de segmento pode ser realizada.

Manipulação de exceção

  Outro segmento anormal, o segmento principal pode capturá-lo?

public static void Main(){

    try{

        new Thread(Go).Start();

    }

    catch (Exception ex){

        // 其它线程里面的异常,我们这里面是捕获不到的。

        Console.WriteLine("Exception!");

    }

}

static void Go() { throw null; }

Em seguida, atualizar da Task-lo?

public static void Main(){

    try{

        var task = Task.Run(() => { Go(); });

        task.Wait();  // 在调用了这句话之后,主线程才能捕获task里面的异常

 

        // 对于有返回值的Task, 我们接收了它的返回值就不需要再调用Wait方法了

        // GetName 里面的异常我们也可以捕获到

        var task2 = Task.Run(() => { return GetName(); });

        var name = task2.Result;

    }

    catch (Exception ex){

        Console.WriteLine("Exception!");

    }

}

static void Go() { throw null; }

static string GetName() { throw null; }

Um pequeno exemplo de assíncrono compreensão e aguardam

static void Main(string[] args){

    Test(); // 这个方法其实是多余的, 本来可以直接写下面的方法

    // await GetName() 

    // 但是由于控制台的入口方法不支持async,所有我们在入口方法里面不能 用 await

             

    Console.WriteLine("Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId);

}

 

static async Task Test(){

    // 方法打上async关键字,就可以用await调用同样打上async的方法

    // await 后面的方法将在另外一个线程中执行

    await GetName();

}

 

static async Task GetName(){

    // Delay 方法来自于.net 4.5

    await Task.Delay(1000);  // 返回值前面加 async 之后,方法里面就可以用await了

    Console.WriteLine("Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId);

    Console.WriteLine("In antoher thread.....");

}

protótipo aguardam

  Após o aguardam ordem de execução 

 

 

Graças locus da correção, aguardam mais tarde não vai abrir um novo segmento (aguardam nunca abra um novo segmento), de modo que o diagrama acima é um pequeno problema.

  await não vai abrir um novo segmento, o segmento atual será sempre ir para baixo até encontrar o método assíncrono real (por exemplo HttpClient.GetStringAsync), dentro deste método será usado para abrir uma linha Task.Run ou Task.Factory.StartNew. Se o método não é o método .NET Async fornece-nos, precisamos criar uma Task-se, vai realmente ir para criar um thread .

static void Main(string[] args)

{

    Console.WriteLine("Main Thread Id: {0}\r\n", Thread.CurrentThread.ManagedThreadId);

    Test();

    Console.ReadLine();

}

 

static async Task Test()

{

    Console.WriteLine("Before calling GetName, Thread Id: {0}\r\n", Thread.CurrentThread.ManagedThreadId);

    var name = GetName();   //我们这里没有用 await,所以下面的代码可以继续执行

    // 但是如果上面是 await GetName(),下面的代码就不会立即执行,输出结果就不一样了。

    Console.WriteLine("End calling GetName.\r\n");

    Console.WriteLine("Get result from GetName: {0}", await name);

}

 

static async Task<string> GetName()

{

    // 这里还是主线程

    Console.WriteLine("Before calling Task.Run, current thread Id is: {0}", Thread.CurrentThread.ManagedThreadId);

    return await Task.Run(() =>

    {

        Thread.Sleep(1000);

        Console.WriteLine("'GetName' Thread Id: {0}", Thread.CurrentThread.ManagedThreadId);

        return "Jesse";

    });

}

Vejamos esse quadro:

  1. Digite o thread principal começa a execução
  2. método assíncrono chamada retorna uma tarefa, prestar atenção desta vez outro segmento já está em execução, que é GetName dentro da Task  começou a trabalhar
  3. O thread principal continuam a descer
  4. Passo 3 e Passo 4 são realizados em simultâneo, e o segmento principal não está suspensa a espera
  5. Se outro segmento terminar, name.IsCompleted = true, os principais trava rosca ainda não, ter um resultado direto disso. Se houver outra discussão terminou com, name.IsCompleted = false, então pendurar a thread principal para esperar até que ele retorna os resultados.

Apenas assíncrona método antes da chamada para add a esperam?

 

 

static void Main(){

    Test();

    Console.ReadLine();

}

 

static async void Test(){

    Task<string> task = Task.Run(() =>{

        Thread.Sleep(5000);

        return "Hello World";

    });

    string str = await task;  //5 秒之后才会执行这里

    Console.WriteLine(str);

}

A resposta é óbvia: o aguardam não é dirigida a um assíncrono método, mas retornou para nós para o método Task assíncrona , razão pela qual todos os métodos assíncronos deve ser devolvido para nós de tarefas. Então, nós também pode adicionar palavras-chave aguardam na frente da tarefa, isso na verdade eu tenho que esperar para dizer ao compilador que o valor de retorno de Task ou Task, etc. Após isso está acabado para continuar a ir para baixo.

Não palavras-chave aguardam, como confirmar a tarefa é concluída?

static void Main(){

    var task = Task.Run(() =>{

        return GetName();

    });

 

    task.GetAwaiter().OnCompleted(() =>{

        // 2 秒之后才会执行这里

        var name = task.Result;

        Console.WriteLine("My name is: " + name);

    });

 

    Console.WriteLine("主线程执行完毕");

    Console.ReadLine();

}

 

static string GetName(){

    Console.WriteLine("另外一个线程在获取名称");

    Thread.Sleep(2000);

    return "Jesse";

}

 

Diferença Task.GetAwaiter () e aguardar a tarefa de?

  • Depois de adicionar palavra-chave await, a trás código irá ser suspenso de esperar até que a tarefa é o retorno final para os valores do tempo vai continuar a descer, desta vez o thread principal em um estado suspenso.
  • método GetAwaiter retorna um objeto awaitable (herdado método INotifyCompletion.OnCompleted) que acabamos de passar um delegado para ele, como a conclusão da tarefa será executada esta comissão, mas que não afeta o segmento principal , o seguinte código será executado imediatamente. É por isso que temos os resultados de que a primeira frase seria "o segmento principal está consumado"!

Tarefa Como fazer os principais trava rosca esperando?

  A descrição acima é parte do lado direito sem suspender o segmento principal, e nós ainda esperamos um pouco diferente, como pendurar o segmento principal antes de obter os resultados da Task-lo?

static void Main(){

    var task = Task.Run(() =>{

        return GetName();

    });

 

    var name = task.GetAwaiter().GetResult();

    Console.WriteLine("My name is:{0}",name);

 

    Console.WriteLine("主线程执行完毕");

    Console.ReadLine();

}

 

static string GetName(){

    Console.WriteLine("另外一个线程在获取名称");

    Thread.Sleep(2000);

    return "Jesse";

}

Task.GetAwait () método irá nos dar um objeto awaitable retorno chamando o método GetResult do objeto irá suspender o segmento principal, é claro, nem todos os casos estão pendentes. Lembre-se a natureza de nossa tarefa dele? No início da hora de começar outra thread para executar a tarefa, quando chamamos o resultado de tempo se essa tarefa foi executada, o segmento principal não está esperando pode obter um resultado, e que o thread principal está terminado, se não houver direta Nós temos que pendurar espera.

essência await é chamando o método GetResult objeto awaitable

 

static async Task Test(){

    Task<string> task = Task.Run(() =>{

        Console.WriteLine("另一个线程在运行!");  // 这句话只会被执行一次

        Thread.Sleep(2000);

        return "Hello World";

    });

 

    // 这里主线程会挂起等待,直到task执行完毕我们拿到返回结果

    var result = task.GetAwaiter().GetResult(); 

    // 这里不会挂起等待,因为task已经执行完了,我们可以直接拿到结果

    var result2 = await task;    

    Console.WriteLine(str);

}

Até agora, aguardam o mistério acabou, receber comentários. Desfrute de codificação! :) 

 

Lançado seis artigos originais · Louvor obteve 189 · vista 280 000 +

Acho que você gosta

Origin blog.csdn.net/newbie_xymt/article/details/104271672
Recomendado
Clasificación