Когда следует избегать Async Await - PullRequest
0 голосов
/ 02 октября 2019

Async / Await - хороший способ кодирования адаптивного графического интерфейса, но, как я полагаю, сыр здесь не бесплатный. Я думаю, что единственный способ реализовать оператор Await - это стек памяти. Каждый раз, когда вы вызываете Await, в стек памяти добавляется новый указатель. Поэтому, если вы вызываете часто ожидающие и ожидающие задержки, вы получаете переполнение стека (это ключевое слово, которое вы не можете найти здесь :))

Давайте предположим, что мы периодически проверяем некоторое состояние соединения асинхронно. Создайте простой проект форм Windows с Form1 и код формы здесь.

using System;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace testasync
{
    public partial class Form1 : Form
    {
        int CallCount = 0;
        int CalBackCount = 0;
        Random r = new Random();

        private Button butStart = new Button();
        private Button butStop = new Button();
        private Timer timer1 = new Timer();
        private Label labCalls =new Label();
        private Label labReturns = new Label();

        public Form1()
        {
            this.ClientSize = new System.Drawing.Size(450, 200);

            butStart.Location = new System.Drawing.Point(51, 38);
            butStart.Size = new System.Drawing.Size(139, 47);
            butStart.Text = "Start";
            butStart.Click += new System.EventHandler(this.butStart_Click);

            butStop.Location = new System.Drawing.Point(237, 38);
            butStop.Size = new System.Drawing.Size(139, 47);
            butStop.Text = "Stop";
            butStop.Click += new System.EventHandler(this.butStop_Click);

            labCalls.Location = new System.Drawing.Point(48, 149);
            labCalls.Size = new System.Drawing.Size(100, 23);

            labReturns.Location = new System.Drawing.Point(237, 149);
            labReturns.Size = new System.Drawing.Size(100, 23);

            Controls.Add(this.labCalls);
            Controls.Add(this.labReturns);
            Controls.Add(this.butStart);
            Controls.Add(this.butStop);


            timer1.Interval = 5;
            timer1.Tick += new System.EventHandler(this.timer1_Tick);
        }

        private void butStart_Click(object sender, EventArgs e)
        {
            timer1.Enabled = true;
        }

        private void butStop_Click(object sender, EventArgs e)
        {
            timer1.Enabled = false;
        }


        private async Task myWork()
        {
            CallCount++;
            await Task.Delay(2000);
            if (r.Next(100)>10) //Check Connection
                await Task.Delay(100000000);
            CalBackCount++;
        }

        private async void timer1_Tick(object sender, EventArgs e)
        {
            labCalls.Text = CallCount.ToString();
            await myWork();
            labReturns.Text = CalBackCount.ToString();
        }
    }
}

вместо проверки соединения я использую случайную проверку, чтобы долго ждать ответа на соединение.

Если мы запустим проекти нажмите кнопку «Пуск», и мы увидим, что потребление памяти приложением увеличивается со временем. Поэтому я полагаю, что это неправильный способ использовать оператор Await, я думаю, что лучший способ - использовать многопоточность с делегатами или симпатичный компонент BackgroundWorker с событиями прогресса. Или, может быть, есть лучшие решения?

1 Ответ

1 голос
/ 02 октября 2019

Ваши предположения о том, как работает async-await, неверны.

Каждый асинхронный метод будет преобразован в конечный автомат, который разделяет метод на несколько методов (части между началом, ожиданием и концом)и организует его выполнение.

Мошеннический асинхронный метод с большей вероятностью исчерпает кучу, чем стек.

...