我有一個應用程式,其中一個按鈕開始創建 XML。在每個XML 創建結束時,SendInvoice函式發送它,接收回應,一個函式 ( ParseResponse ) 決議回應并執行所需的資料庫操作。
這個想法是,當所有的 XML 被創建和發送時,應用程式必須關閉。問題是我失去了對 async 的控制,并且應用程式似乎在它實際完成所有作業之前就關閉了。此外,在處理前一個 XML 之前發送 XML。
ParseResponse 函式不是異步的。
這是 SendInvoice 函式。
你能提出任何好的做法嗎?
先感謝您。
public async void SendInvoice(string body)
{
Cursor.Current = Cursors.WaitCursor;
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
var uri = "https://xxxx.xxx/SendInvoices?" queryString;
HttpResponseMessage response;
// Request body
byte[] byteData = Encoding.UTF8.GetBytes(body);
using (var content = new ByteArrayContent(byteData))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
response = await client.PostAsync(uri, content);
string responsebody = await response.Content.ReadAsStringAsync();
ParseResponse(response.ToString());
ParseResponse(responsebody);
}
}
其余代碼
private void button1_Click(object sender, EventArgs e)
{
For
{
......
SendInvoice(xml)
}
System.Windows.Forms.Application.Exit();
}
uj5u.com熱心網友回復:
由于您是從事件處理程式呼叫該方法,這是async void可以接受的情況,請更改您的按鈕單擊處理程式方法簽名以使用async,我還添加了一些ConfigureAwait(false)異步方法呼叫 -最佳實踐-呼叫-配置等待-為- all-server-side-code和為什么是writing-configureawaitfalse-on-line-with-await-always-recommended:
private async void button1_Click(object sender, EventArgs e)
{
//since you are using a for-loop, I'd suggest adding each Task
//to a List and awaiting all Tasks to complete using .WhenAll()
var tasks = new List<Task>();
FOR
{
......
//await SendInvoice(xml).ConfigureAwait(false);
tasks.Add(SendInvoice(xml));
}
await Task.WhenAll(tasks).ConfigureAwait(false);
System.Windows.Forms.Application.Exit();
}
并更改您的SendInvoice方法簽名以回傳Task
public async Task SendInvoice(string body)
{
Cursor.Current = Cursors.WaitCursor;
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
var uri = "https://xxxx.xxx/SendInvoices?" queryString;
HttpResponseMessage response;
// Request body
byte[] byteData = Encoding.UTF8.GetBytes(body);
using (var content = new ByteArrayContent(byteData))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
response = await client.PostAsync(uri, content).ConfigureAwait(false);
string responsebody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
ParseResponse(response.ToString());
ParseResponse(responsebody);
}
}
uj5u.com熱心網友回復:
我很習慣多執行緒編程,我花了一些時間來理解異步編程,因為它真的與多執行緒無關。它是關于使用單個執行緒或少量執行緒做更多事情。
當 CPU 等待處理以外的事情時,異步代碼是有益的。例如:等待網路回應、等待從磁盤讀取資料、等待單獨的行程(例如資料庫服務器)。
它為您正在運行的執行緒提供了一種在您等待時做其他事情的方法。C# 使用Task. 任務是一些正在完成的作業,它可以正在運行,也可以正在等待,等待時不需要附加執行緒。
所有異步函式都必須回傳一個 Task 才能有用。所以你的功能應該是:
public async Task SendInvoice() {
...
async編譯器使用該關鍵字將您的函式自動包裝在任務物件中,因此您無需擔心很多細節。您只需await在呼叫另一個異步函式時使用。您可以自己做更多的作業來創建任務或從另一個異步函式回傳任務,甚至呼叫多個異步函式并一起等待所有它們。
例如,如果您的異步方法回傳一個值,請使用通用 Task: Task<String>。
在Task從任務完成前異步方法回傳。這就是允許執行緒被其他東西使用的原因,但它必須回到那個起點,這就是為什么異步編程你會聽到“一路異步”。在它回傳到有多個任務需要平衡的呼叫者之前,它實際上沒有任何好處,這通常是您的應用程式或 Web 請求的入口點。
您可以使 C#Main方法異步,但除非您的行程確實在同時執行多項操作,否則這通常無關緊要。對于 Web 應用程式,它只能處理多個請求。對于獨立的應用程式,這意味著您可以查詢多個 API,同時發出多個 Web 請求或資料庫查詢,并等待它們,只需使用單個執行緒。顯然,這可以使事情更快(至少在本地,外部資源可能有更多作業要做)。
對于防止程式退出的簡單方法,如果您有異步main,只需await呼叫SendInvoice. 如果您的 main 不是異步的,您可以使用以下內容:
SendInvoice().Wait()
或者
SendInvoice().Result
使用Wait()orResult將鎖定執行緒直到任務完成。它通常會使該執行緒專供該任務使用,因此該執行緒不能用于任何其他任務。如果執行緒池中有更多執行緒,其他任務可能會繼續運行,但通常在單個任務上使用 Wait/Result 會失去異步編程的意義,因此請記住這一點。
編輯 現在您已經發布了您的呼叫代碼,看起來您的呼叫處于回圈中。這是利用異步呼叫并立即發送所有發票的好機會。
private async void button1_Click(object sender, EventArgs e)
{
List<Task> tasks = new List<Task>();
FOR
{
......
t = SendInvoice(xml).ConfigureAwait(false);
tasks.Add(t)
}
await Task.WhenAll(tasks).ConfigureAwait(false);
System.Windows.Forms.Application.Exit();
}
這將發送所有發票,然后從處理程式回傳,然后在收到所有回應后退出。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/345415.html
