Фоновый рабочий поток и вызовы asyn c - PullRequest
1 голос
/ 07 мая 2020

Я работаю над приложением c#, у него есть фоновый поток, который выполняет множество задач, например, вызывает конечную точку HTTP / REST, выполняет базовые c вычисления, отправляет данные через сокет и c. Все операции помещаются в очередь фонового потока, он выводит их из очереди по отдельности, обрабатывает их, а затем переходит к следующему.

Я думал об использовании asyn c в фоновом потоке, например, вызовите HTTP конечная точка, использующая семантику async / await, но не знаю, как это повлияет на фоновый поток. Допустим, фоновый поток вызывает конечную точку HTTP, используя asyn c, как мне структурировать код, чтобы он исключал из очереди следующий пакет и обрабатывал его?

Ответы [ 2 ]

2 голосов
/ 08 мая 2020

Я думал об использовании asyn c в фоновом потоке, например, вызовите конечную точку HTTP с использованием семантики async / await, но не уверен, как это повлияет на фоновый поток. Допустим, фоновый поток вызывает конечную точку HTTP с использованием asyn c, как мне структурировать код, чтобы он выводил из очереди следующий пакет и обрабатывал его?

await имеет «крючки», которые вы можете использовать для управления поведением возобновления по умолчанию. await сам по себе (если используется полностью) "уступит" вашему циклу обработки сообщений; это не проблема. Но по умолчанию, когда await возобновляет выполнение своего метода, этот метод будет работать в потоке пула потоков, а не в выделенном фоновом потоке.

Если вы хотите, чтобы код после await возобновился на вашем фоне thread, вам нужно создать SynchronizationContext, в котором очереди работают с очередью фонового потока, и убедиться, что он установлен как текущий SynchronizationContext для любого кода, который выполняется в фоновом потоке. Я написал AsyncContextThread, это фоновый поток с очередью сообщений и SynchronizationContext; это должно быть хорошей отправной точкой.

0 голосов
/ 08 мая 2020

Вы можете смешивать как async / await, так и работать в фоновом потоке. Async / Await никак не влияет на фоновый поток. Но, пожалуйста, помните, что под async / await задействованы Task (и конечный автомат).

Интересный факт - когда вы декомпилируете код async / await -> там нет async / await; ) Можно сказать, что это синтаксис suger.

Дополнительная информация о том, как это организовано - например, здесь: https://ranjeet.dev/understanding-how-async-state-machine-works/

Так может случиться, что когда вы возвращаетесь из операции asyn c (например, вы начнете получать ответ от HTTP-запроса) - возможно, вы окажетесь в другом потоке, а остальная часть кода будет обработана в другом потоке. Обычно это не проблема, но иногда это имеет значение (например, на ASP. NET - httpcontext может быть потерян из-за этого)

Вы также спросили: «Как мне структурировать код? "И в этом прелесть async / await. Вы не делаете :) Все, что вам нужно изменить, это изменить все на async / await - потому что правило: «Asyn c all way» очень важно »Подробнее о важных правилах асинхронного программирования здесь: https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming

Так, например, если у вас был такой код:

public string SendHttpRequest()
{
    using (var client = new WebClient())
    {
        return client.DownloadString(new Uri("http://www.example.com/example.aspx"));
    }
}

, вам просто нужно будет изменить его на:

public async Task<string> SendHttpRequestAsync()
{
    using (var client = new WebClient())
    {
        return await client.DownloadStringTaskAsync("http://www.example.com/example.aspx");
    }
}

И затем, конечно, каждое место в коде - вам нужно изменить на asyn c (и вы должны вызвать этот метод и все методы, которые станут asyn c с await). Это правило «asyn c полностью "Не go соблазняйтесь использовать это где-нибудь в коде:

SendHttpRequestAsync().Result --> beacause it saves you from adding async on the method;)

Тогда вы упускаете смысл использования асинхронных функций, и действительно могут произойти какие-то постельные вещи (попробуйте сделать что-нибудь вот так в Winforms с каким-то событием OnClick :))

...