我有一個 Blazor WASM 應用程式,它需要在不阻塞 UI 的情況下每秒呼叫一個 API。此代碼演示了我如何嘗試這樣做:
List<int> testList = new();
testList.Add(1);
testList.Add(2);
testList.Add(3);
testList.Add(4);
List<int> emptyTestlist = new();
CancellationTokenSource cts;
Test();
void Test()
{
Parallel.Invoke(async () =>
{
do
{
Console.WriteLine("Start");
await Task.Delay(1000);
await Test2();
Console.WriteLine("END");
} while (true);
});
}
Console.ReadLine();
async ValueTask Test2()
{
emptyTestlist.Clear();
cts = new();
await Parallel.ForEachAsync(testList, cts.Token, async (test, token) =>
{
await Test4(test);
});
foreach (var test in emptyTestlist)
{
await Test3(test);
}
}
async Task Test4(int i)
{
await Task.Delay(300);
//Console.WriteLine("if I Add this console.WriteLine It's added perfectly");
emptyTestlist.Add(i);
Console.WriteLine($"from TEST4: {i}");
}
async Task Test3(int i)
{
Console.WriteLine($"TEST3 {i}.");
await Task.Delay(1000);
Console.WriteLine($"TEST3 {i}, after 1sec");
}
如果我評論該行Console.WriteLine("if I Add this console.WriteLine It's added perfectly");,它并沒有完美添加。(emptyTestlist.Count并不總是 4)。但是如果我Console.WriteLine在emptyTestlist.Add(i)它正常作業之前添加(emptyTestlist.Count總是 4)。
我不知道如何解決。有什么問題?
uj5u.com熱心網友回復:
輪詢 API 的最簡單方法是使用計時器:
@code {
private List<Customer> custs=new List<Customer>();
private System.Threading.Timer timer;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
custs = await Http.GetFromJsonAsync<List<Customer>>(url);
timer = new System.Threading.Timer(async _ =>
{
custs = await Http.GetFromJsonAsync<List<Customer>>("/api/customers");
InvokeAsync(StateHasChanged);
}, null, 1000, 1000);
}
在這種情況下InvokeAsync(StateHasChanged);是需要的,因為狀態是從計時器執行緒修改的,而 Blazor 不知道資料已更改。
但是,如果我們想將結果添加到串列中,我們必須使用鎖或執行緒安全集合,例如ConcurrentQueue.
@code {
private ConcurrentQueue<Customer> custs=new ConcurrentQueue<Customer>();
private System.Threading.Timer timer;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
custs = await Http.GetFromJsonAsync<List<Customer>>(url);
timer = new System.Threading.Timer(async _ =>
{
var results = await Http.GetFromJsonAsync<List<Customer>>("/api/customers");
foreach(var c in results)
{
custs.Enqueue(c);
}
InvokeAsync(StateHasChanged);
}, null, 1000, 1000);
}
每秒輪詢一個 API 以防萬一有任何新資料雖然效率不高。最好讓 API 使用例如SignalR或Push Notifications通知客戶端任何新資料
借用檔案示例,這足以從服務器接收訊息:
@code {
private HubConnection hubConnection;
private List<string> messages = new List<string>();
private string userInput;
private string messageInput;
protected override async Task OnInitializedAsync()
{
hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/chathub"))
.Build();
hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
var encodedMsg = $"{user}: {message}";
messages.Add(encodedMsg);
StateHasChanged();
});
await hubConnection.StartAsync();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/311136.html
標籤:C# 异步等待 blazor-webassembly 并行.foreach .net-6.0
上一篇:修改和驗證資料表c#中的欄位
