Нередко программа выполняет такие операции, которые могут занять продолжительное время, например, обращение к сетевым ресурсам, чтение-запись файлов, обращение к базе данных и т.д. Такие операции могут серьезно нагрузить приложение. Особенно это актуально в графических (десктопных или мобильных) приложениях, где продолжительные операции могут блокировать интерфейс пользователя и негативно повлиять на желание пользователя работать с программой, или в веб-приложениях, которые должны быть готовы обслуживать тысячи запросов в секунду. В синхронном приложении при выполнении продолжительных операций в основном потоке этот поток просто бы блокировался на время выполнения операции. И чтобы продолжительные операции не блокировали общую работу приложения, в C# можно задействовать асинхронность.
Асинхронность позволяет вынести отдельные задачи из основного потока в специальные асинхронные методы и при этом более экономно использовать потоки. Асинхронные методы выполняются в отдельных потоках. Однако при выполнении продолжительной операции поток асинхронного метода возвратится в пул потоков и будет использоваться для других задач. А когда продолжительная операция завершит свое выполнение, для асинхронного метода опять выделяется поток из пула потоков, и асинхронный метод продолжает свою работу.
Сделал Python программу для отслеживания курса валют
Ключевыми для работы с асинхронными вызовами в C# являются два оператора: async и await , цель которых — упростить написание асинхронного кода. Они используются вместе для создания асинхронного метода.
Асинхронный метод обладает следующими признаками:
- В заголовке метода используется модификатор async
- Метод содержит одно или несколько выражений await
- В качестве возвращаемого типа используется один из следующих:
- void
- Task
- Task
- ValueTask
Асинхронный метод, как и обычный, может использовать любое количество параметров или не использовать их вообще. Однако асинхронный метод не может определять параметры с модификаторами out , ref и in .
Также стоит отметить, что слово async , которое указывается в определении метода, НЕ делает автоматически метод асинхронным. Оно лишь указывает, что данный метод может содержать одно или несколько выражений await .
Рассмотрим простейший пример определения и вызова асинхронного метода:
await PrintAsync(); // вызов асинхронного метода Console.WriteLine(«Некоторые действия в методе Main»); void Print() < Thread.Sleep(3000); // имитация продолжительной работы Console.WriteLine(«Hello METANIT.COM»); >// определение асинхронного метода async Task PrintAsync() < Console.WriteLine(«Начало метода PrintAsync»); // выполняется синхронно await Task.Run(() =>Print()); // выполняется асинхронно Console.WriteLine(«Конец метода PrintAsync»); >
Здесь прежде всего определен обычный метод Print, который просто выводит некоторую строку на консоль. Для имитации долгой работы в нем используется задержка на 3 секунд с помощью метода Thread.Sleep() . То есть условно Print — это некоторый метод, который выполняет некоторую продолжительную операцию. В реальном приложении это могло бы быть обращение к базе данных или чтение-запись файлов, но для упрощения понимания он просто выводит строку на консоль.
Программа на Python для управления компьютером / Python + PyAutoGUI
Также здесь определен асинхронный метод PrintAsync() . Асинхронным он является потому, что имеет в определении перед возвращаемым типом модификатор async , его возвращаемым типом является Task, и в теле метода определено выражение await .
Стоит отметить, что явным образом метод PrintAsync не возвращает никакого объекта Task, однако поскольку в теле метода применяется выражение await , то в качестве возвращаемого типа можно использовать тип Task.
Оператор await предваряет выполнение задачи, которая будет выполняться асинхронно. В данном случае подобная операция представляет выполнение метода Print:
await Task.Run(()=>Print());
По негласным правилам в названии асинхроннных методов принято использовать суффикс Async — Print Async () , хотя в принципе это необязательно делать.
И затем в программе (в данном случае в методе Main) вызывается этот асинхронный метод.
await PrintAsync(); // вызов асинхронного метода
Посмотрим, какой у программы будет консольный вывод:
Начало метода PrintAsync Hello METANIT.COM Конец метода PrintAsync Некоторые действия в методе Main
Разберем поэтапно, что здесь происходит:
- Запускается программа, а точнее метод Main, в котором вызывается асинхронный метод PrintAsync.
- Метод PrintAsync начинает выполняться синхронно вплоть до выражения await.
Console.WriteLine(«Начало метода PrintAsync»); // выполняется синхронно
Асинхронный метод Main
Стоит учитывать, что оператор await можно применять только в методе, который имеет модификатор async . И если мы в методе Main используем оператор await , то метод Main тоже должен быть определен как асинхронный. То есть предыдущий пример фактически будет аналогичен следующему:
class Program < async static Task Main(string[] args) < await PrintAsync(); // вызов асинхронного метода Console.WriteLine(«Некоторые действия в методе Main»); void Print() < Thread.Sleep(3000); // имитация продолжительной работы Console.WriteLine(«Hello METANIT.COM»); >// определение асинхронного метода async Task PrintAsync() < Console.WriteLine(«Начало метода PrintAsync»); // выполняется синхронно await Task.Run(() =>Print()); // выполняется асинхронно Console.WriteLine(«Конец метода PrintAsync»); > > >
Задержка асинхронной операции и Task.Delay
В асинхронных методах для остановки метода на некоторое время можно применять метод Task.Delay() . В качестве параметра он принимает количество миллисекунд в виде значения int, либо объект TimeSpan, который задает время задержки:
await PrintAsync(); // вызов асинхронного метода Console.WriteLine(«Некоторые действия в методе Main»); // определение асинхронного метода async Task PrintAsync() < await Task.Delay(3000); // имитация продолжительной работы // или так //await Task.Delay(TimeSpan.FromMilliseconds(3000)); Console.WriteLine(«Hello METANIT.COM»); >
Причем метод Task.Delay сам по себе представляет асинхронную операцию, поэтому к нему применяется оператор await.
Преимущества асинхронности
Выше приведенные примеры являются упрощением, и вряд ли их можно считать показательным. Рассмотрим другой пример:
PrintName(«Tom»); PrintName(«Bob»); PrintName(«Sam»); void PrintName(string name) < Thread.Sleep(3000); // имитация продолжительной работы Console.WriteLine(name); >
Stefan-dev94 / Консольное меню
Задача: При помощи всего, что вы изучили, создать приложение, которое может обрабатывать команды. Т.е. вы создаете меню, ожидаете ввода нужной команды, после чего выполняете действие, которое присвоено этой команде. Примеры команд (Требуется 4-6 команд, придумать самим) SetName – установить имя ChangeConsoleColor- изменить цвет консоли SetPasswo…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
using System; |
namespace ConsoleApp1 |
class Program |
static void Main(string[] args) |
int userInput; |
int setColor; |
string password; |
string setName=»»; |
string setPassword=»1234″; |
bool menuActive = true; |
while (menuActive) |
Console.WriteLine(«*** Выберите нужную команду *** «); |
Console.WriteLine(«n1- Установить имя. n2- Выберать цвет текста. n3- Установить пароль. n4- Вывести имя. n5- Выход»); |
userInput = Convert.ToInt32(Console.ReadLine()); |
switch (userInput) |
case 1: |
Console.Write(«Установите имя:»); |
setName = Console.ReadLine(); |
Console.Clear(); |
break; |
case 2: |
Console.Write(«1: Синий. n2: Красный. n3: Зеленный «); |
setColor = Convert.ToInt32(Console.ReadLine()); |
if(setColor == 1) |
Console.ForegroundColor = ConsoleColor.Blue; |
Console.Clear(); |
> |
else if(setColor == 2) |
Console.ForegroundColor = ConsoleColor.Red; |
Console.Clear(); |
> |
else if(setColor == 3) |
Console.ForegroundColor = ConsoleColor.Green; |
Console.Clear(); |
> |
break; |
case 3: |
Console.Write(«Установите пароль:»); |
setPassword = Console.ReadLine(); |
Console.Clear(); |
break; |
case 4: |
Console.Write(«Введите пароль: «); |
password = Console.ReadLine(); |
if (password == setPassword) |
Console.WriteLine(«Имя пользователя: » + setName); |
> |
else |
Console.WriteLine(«Пароль неверный.»); |
> |
break; |
case 5: |
Console.WriteLine(«Вы вышли из меню!»); |
menuActive = false; |
break; |
> |
> |
> |
> |
> |
Источник: gist.github.com
Программирование на C, C# и Java
Уроки программирования, алгоритмы, статьи, исходники, примеры программ и полезные советы
Потоки в C# для начинающих: разбор, реализация, примеры
В данной статье мы расскажем, что такое потоки в C#, приоритеты потоков и их типы, покажем, как работать с потоками и как ими управлять, создадим несколько наглядных примеров, объясняющих их работу.
Что такое потоки в C#
Если говорить простым языком, то поток — это некая независимая последовательность инструкций для выполнения того или иного действия в программе. В одном конкретном потоке выполняется одна конкретная последовательность действий.
Совокупность таких потоков, выполняемых в программе параллельно называется многопоточностью программы.
Следует также запомнить, что в действительности потоки выполняются всё-таки не совсем параллельно. Дело в том, что процессор физически не может обрабатывать параллельно несколько инструкций или процессов. Однако его вычислительной мощи хватает настолько, что он может выполнять все операции по небольшому фрагменту по очереди, отводя на каждый такой фрагмент по очень маленькому кусочку времени, настолько, что кажется, будто все процессы в компьютере выполняются параллельно.
Точно такая же ситуация происходит и с потоками. Если в программе имеется 3 потока, то сначала выполняется кусочек кода из одного потока, потом кусочек кода из другого, затем — из третьего, после чего процессор снова переходит к какому-либо из двух других потоков. Выбор, какой поток необходимо назначить для выполнения в данный момент остаётся за процессором. Происходит это в доли миллисекунд, поэтому происходит ощущение параллельной работы потоков.
Стандартно в проектах Visual Studio существует только один основной поток — в методе Main. Всё, что в нём выполняется — выполняется последовательно строка за строкой. Но при необходимости можно «распараллелить» выполняемые процессы при помощи потоков.
Для лучшего осознания можно представить следующий пример. Допустим, что наша программа и данные, которые в ней содержатся — это офис с различными предметами (папками, столами, стульями, ручками), а потоки — это работники данного офиса (изначально у нас только один работник, выполняющий всю работу), и каждый работник занимается теми делами, которые ему было сказано выполнять. Работники могут выполнять одинаковые задания, а могут и различные. В случае выполнения какой-либо одной задачи, несколько работников справятся быстрее, чем один.
Например, если один работник будет собирать шкаф час, то вдвоём они могут управиться уже за полчаса. Однако не стоит переусердствовать в количестве работников (потоков). Математически, если нанять 4 работника, то шкаф соберется за 15 минут, если нанять 60 работников — за 1 минуту, а если нанять 3600, то вообще за секунду, но ведь на деле это неверно. Работники будут только мешать друг другу, толкаться, отнимать друг у друга детали, и процесс сборки шкафа может затянуться очень надолго.
Так же и с потоками. Чем больше потоков, тем выше вероятность, что они будут мешать друг другу выполнять свою работу. Например, если заставить работать огромное количество потоков с одними и теми же данными, потокам придётся выстраиваться в очередь для их обработки (например, если тем же 3600 рабочим дать какое-либо письменное задание, но предоставить им для этого дела всего одну ручку, то работникам, естественно, придётся становиться друг за другом в очередь за ручкой, чтобы после её получения выполнить поставленную задачу. Времени это займёт довольно много).
Итог: потоки надо распределять с умом и исключительно в случаях, когда это действительно необходимо для ускорения работы программы либо для повышения производительности.
Язык C# имеет встроенную поддержку многопоточности, а среда .NET Framework предоставляет сразу несколько классов для работы с потоками, что в купе очень помогает гибко и правильно реализовывать и настраивать многопоточность в проектах.
В среде .NET Framework существует два типа потоков: основной и фоновый (вспомогательный). В целом отличие между ними одно — если первым завершится основной поток, то фоновые потоки в его процессе будут также принудительно остановлены, если же первым завершится фоновый поток, то это не повлияет на остановку основного потока — тот будет продолжать функционировать до тех пор, пока не выполнит всю работу и самостоятельно не остановится. Обычно при создании потока ему по-умолчанию присваивается основной тип. О том, как узнать, к какой разновидности относится тот или иной поток, как придать потоку нужный тип, что такое приоритеты и как их устанавливать, и как в целом работать с потоками в C# мы поговорим ниже.
Реализация потоков в C#
Как создавать потоки в C#
Перво-наперво для работы с потоками в C# необходимо подключить специальную директиву:
Источник: vscode.ru