亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

異步操作已取消但仍需要時間來更新網格

異步操作已取消但仍需要時間來更新網格

C#
牧羊人nacy 2022-07-23 09:12:29
我在使異步操作正常工作時遇到了一些麻煩(異步操作的新手)。我的目標是讓“加載數據”按鈕退出并從數據庫中檢索一些數據并填充網格。對于某些用戶而言,數據庫可能有些遠,此操作可能需要一些時間??紤]到這一點,我希望用戶能夠選擇取消并選擇檢索較小的數據集。我主要使用當前流程:用戶單擊“加載數據...”按鈕按鈕更改為“取消”,異步操作開始檢索數據檢索數據并填充網格這一切都運行良好,除了,如果用戶單擊取消,它仍然需要相同的時間來獲取所有數據以使網格變為空。這讓我相信長時間運行的操作實際上并沒有被取消......但是,當我在“FindForLocationAsync”方法中調試時,如果用戶請求取消令牌確實會停止迭代操作并提前從該方法返回消除。很長一段時間以來,我一直在盡可能多地閱讀,但是,我現在陷入了僵局。任何幫助將不勝感激。取消令牌來源CancellationTokenSource cancellationTokenSource = null;按鈕點擊方法private async void btnSearch_Click(object sender, EventArgs e){    gridLog.DataSource = null;    Cursor = Cursors.WaitCursor;    if (btnSearch.Text.ToLower().Contains("load"))    {        btnSearch.Text = "Cancel";        btnSearch.ForeColor = Color.White;        btnSearch.BackColor = Color.Red;        //get params to pass        /* snip */        cancellationTokenSource = new CancellationTokenSource();        await Task.Run(() =>            {                var ds = DocLog.FindForLocationAsync(docType, subType, days, currLocation.ID, cancellationTokenSource.Token).Result;                gridLog.DataSource = ds;            });        btnSearch.Text = "Load Data...";        btnSearch.ForeColor = Color.Black;        btnSearch.BackColor = Color.FromArgb(225, 225, 225);    }    else    {        cancelSearch();        btnSearch.Text = "Load Data...";        btnSearch.ForeColor = Color.Black;        btnSearch.BackColor = Color.FromArgb(225, 225, 225);    }    Cursor = Cursors.Default;}取消方法private void cancelSearch(){    if (cancellationTokenSource != null) cancellationTokenSource.Cancel();}長時間運行方法
查看完整描述

1 回答

?
RISEBY

TA貢獻1856條經驗 獲得超5個贊

這是您修改為 C# 慣用的代碼async

請注意以下事項:

  • 異步代碼通常是指涉及異步 IO 的操作,其中完成信號(和后續完成回調)基本上由硬件中斷和操作系統產生 - 它不應與并發(即多線程)混淆,即使在另一個線程上運行的代碼也可以在概念上被建模為 a Tasktoo(實際上,Task用于多線程 ( Task.Run) 和 async-IO)。

    • 無論如何,重點是:如果您使用的是async-IO API(例如SqlDataReader、FileStreamNetworkStream等),那么您可能不想使用Task.Run.

  • 除了必須在 UI 線程中運行的代碼(即 WinForms 和 WPF UI 代碼)之外,您應該始終使用它.ConfigureAwait(false)來允許在可用的后臺線程中調用完成回調,這意味著 UI 線程不會被迫運行后臺代碼.

  • 一般來說,永遠不要使用Task<T>.Resultor Task.Wait(),因為它們會阻塞線程并引入死鎖的風險(因為不能在阻塞的線程上運行延續回調)。僅Task<T>.Result在您驗證任務已完成(或僅執行await task)后使用。

  • 您應該將 傳遞給您調用的CancellationToken每個子方法。Async

其他挑剔:

  • 您可以using()在同一縮進級別組合語句并SqlConnection.OpenAsync在創建SqlCommand.

  • camelCase參數不應該PascalCase。

  • 對實例成員(字段、方法、屬性等)的引用應加上前綴,this.以便在視覺上與本地標識符區分開來。

  • 這樣做if( this.x != null ) this.x.Foo()并不完全安全,因為在多線程程序x中,可以在調用和調用之間用另一個值替換。而是使用保留本地參考的操作員來防止地毯從您下方拉出(它的工作原理如下:保證是線程安全的)。if.Foo()?.X lx = this.x; if( lx != null ) lx.Foo()

  • BindingList是(可以說)一個 UI 組件,不應該像你的FindForLocationAsync方法那樣從概念上的“背景”函數返回,所以我返回 a List<T>,然后 UI 將List<T>a 包裝在BindingList<T>.

代碼:

private async void btnSearch_Click(object sender, EventArgs e)

{

    this.gridLog.DataSource = null;

    this.Cursor = Cursors.WaitCursor;


    if (this.btnSearch.Text.ToLower().Contains("load"))

    {

        this.btnSearch.Text = "Cancel";

        this.btnSearch.ForeColor = Color.White;

        this.btnSearch.BackColor = Color.Red;


        //get params to pass

        /* snip */


        this.cancellationTokenSource = new CancellationTokenSource();


        List<DocLog> list = await DocLog.FindForLocationAsync(docType, subType, days, currLocation.ID, cancellationTokenSource.Token);

        gridLog.DataSource = new BindingList<DocLog>( list );


        this.btnSearch.Text = "Load Data...";

        this.btnSearch.ForeColor = Color.Black;

        this.btnSearch.BackColor = Color.FromArgb(225, 225, 225);

    }

    else

    {

        CancelSearch();

        this.btnSearch.Text = "Load Data...";

        this.btnSearch.ForeColor = Color.Black;

        this.btnSearch.BackColor = Color.FromArgb(225, 225, 225);

    }


    this.Cursor = Cursors.Default;

}


private void CancelSearch()

{

    this.cancellationTokenSource?.Cancel();

}


public async static Task<List<DocLog>> FindForLocationAsync(string DocType, string SubType, int? LastXDays, Guid LocationID, CancellationToken cancellationToken)

{

    List<DocLog> dll = new List<DocLog>();


    using (SqlConnection sqlConnection = new SqlConnection(Helper.GetConnectionString()))

    using (SqlCommand sqlCommand = sqlConnection.CreateCommand())

    {

        await sqlConnection.OpenAsync(cancellationToken).ConfigureAwait(false);


        sqlCommand.CommandText = (LastXDays == null) ? "DocLogGetAllForLocation" : "DocLogGetAllForLocationLastXDays";

        sqlCommand.CommandType = System.Data.CommandType.StoredProcedure;

        sqlCommand.Parameters.Add("@DocType", SqlDbType.NVarChar, 30).Value = DocType.Trim();

        sqlCommand.Parameters.Add("@SubType", SqlDbType.NVarChar, 30).Value = SubType.Trim();

        sqlCommand.Parameters.Add("@LocationID", SqlDbType.UniqueIdentifier).Value = LocationID;

        if (LastXDays != null) { sqlCommand.Parameters.Add("@NumberOfDays", SqlDbType.Int).Value = LastXDays; }


        using( SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false) )

        {

            while (await sqlDataReader.ReadAsync(cancellationToken).ConfigureAwait(false))

            {

                if (cancellationToken.IsCancellationRequested) break;


                DocLog dl = readData(sqlDataReader);

                dll.Add(dl);

            }

        }

    }


    return dll;

}


查看完整回答
反對 回復 2022-07-23
  • 1 回答
  • 0 關注
  • 150 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號