【发布时间】:2017-03-08 23:03:24
【问题描述】:
我有一个计时器,它每 15 秒调用一次方法,该方法需要一些时间才能完成。
我已尽可能将其转换为async,但它在运行时仍会冻结 UI 近 1 秒,并且由于它每 15 秒运行一次,因此变得很烦人。
知道如何让这个async 方法完全脱离网格运行吗?
这是定时器方法:
public static DispatcherTimer UpdateList = new DispatcherTimer();
//GlobalVars.MainList = new List<string>(); //saved list from previous declaration
public MainFunction()
{
this.InitializeComponent();
UpdateList.Tick += UpdateList_Tick; ;
UpdateList.Interval = new TimeSpan(0, 0, 0, 0, 15000);
UpdateList.Start();
//...
}
private async void UpdateList_Tick(object sender, object e)
{
using (var client = new ImapClient())
{
using (var cancel = new CancellationTokenSource())
{
await client.ConnectAsync("imap.gmail.com", 993, true, cancel.Token);
client.AuthenticationMechanisms.Remove("XOAUTH");
await client.AuthenticateAsync("email.com", "mail12345", cancel.Token);
var inbox = client.Inbox;
await inbox.OpenAsync(FolderAccess.ReadOnly, cancel.Token);
// let's try searching for some messages...
DateTime date = DateTime.Now;
DateTime mondayOfLastWeek = date.AddDays(-(int)date.DayOfWeek - 6);
var query = SearchQuery.DeliveredAfter(mondayOfLastWeek)
.And(SearchQuery.SubjectContains("search"))
.And(SearchQuery.All);
List<string> newList = new List<string>();
foreach (var uid in inbox.Search(query, cancel.Token))
{
var message = inbox.GetMessage(uid, cancel.Token);
string trimmedMSGEmtyLines = Regex.Replace(message.TextBody, @"^\s+$[\r\n]*", "", RegexOptions.Multiline);
newList.Add(message.Date.LocalDateTime + Environment.NewLine + trimmedMSGEmtyLines);
}
await client.DisconnectAsync(true, cancel.Token);
if (!GlobalVars.MainList.SequenceEqual(newList))
{
GlobalVars.MainList = newList;
}
}
}
}
【问题讨论】:
-
是否有理由使用 BackgroundWorker 对您不起作用?
-
async方法中有很多同步代码。对inbox.Search()和Regex.Replace()的调用都可能代价高昂,foreach循环也无济于事。您可以尝试更改为foreach (var uid in await Task.Run(() => inbox.Search(query, cancel.Token)))作为第一次尝试改善延迟。除此之外,如果没有可靠地重现问题的良好 minimal reproducible example,就无法确定您需要修复什么。 -
@khargosh:或者可能是缺乏
async/await的经验。我已经使用BackgroundWorker十五年了,但是一旦我们得到async/await,我就不再再使用BW了。与处理 BW 时相比,代码如此更容易阅读和编写(这在当时很棒,但现在看起来很摇摇晃晃)。 -
另外,由于您已经在使用
async/await并且希望以 15 秒的间隔执行代码,您可以考虑将其放入while循环并使用 @987654345 @ 作为你的计时器,而不是显式地创建一个计时器。 -
“上面的代码确实可以重现,但我不建议你测试它,因为它需要安装包” -- 请阅读minimal reproducible example,这样你就明白了什么这句话的意思。另请参阅How to Ask,尤其是底部链接的文章。 “需要安装包” 只是另一种表示代码不是 一个好的minimal reproducible example。
标签: c# asynchronous timer background uwp