循环完成前退出Dowork的背景工人
我有一个发送ping对象的程序,它会发送ping请求,每个ping对象重复(有8个),等待1000ms,然后重复此操作,但用户指定了很多秒。
当告诉程序以2-3秒的时间运行时间较低时,循环按预期工作。成功输出成功的ping的量(如果它运行了2秒,那么我希望每个ping对象都有2个成功的ping),
这是我收到的意外行为的示例,就是我将秒数设置为运行为10,因此它应该循环遍历8个ping对象中的每个对象,请等待一秒钟,然后重复此for count> 10
我正在调试,循环按预期工作,但随后在6秒后突然退出。我可以看到count = 10
,而i是6
,但是工人退出和runworkerCompleted
方法被调用。
我可以想到线程的问题(?),但我不确定。
这是背景工人dowork
方法:
private async void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
// Create background worker
BackgroundWorker worker = (BackgroundWorker)sender;
// Write to log file
await file.WriteAsync("Starting job...\n");
await file.WriteAsync("Requested amount of pings: " + count + "\n");
// Create date object for logs
DateTime localDate = DateTime.Now;
for (int i = 0; i < count; i++)
{
// Create ping objects
System.Net.NetworkInformation.Ping pinger = new System.Net.NetworkInformation.Ping();
PingReply pingReply;
foreach (Ping pingObj in pings)
{
try
{
pingReply = pinger.Send(pingObj.IpAddress);
// Write log file
await file.WriteLineAsync(localDate.TimeOfDay + " | Friendly Name " + pingObj.FriendlyName + " | Ping: " + pingReply.Address + " | Status " + pingReply.Status + " | Time: " + pingReply.RoundtripTime);
if (pingReply.Status.ToString().Contains("Success"))
{
pingObj.SuccessfulPings += 1;
}
else // Unsuccessful ping has been sent
{
pingObj.FailedPings += 1;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
wait(1000);
}
}
catch (Exception a)
{
Debug.WriteLine(a.ToString());
}
}
这是我开始使用一个按钮的方法:
private void Ping_Btn_Click(object sender, EventArgs e)
{
int counter = 1;
if (backgroundWorker1.IsBusy != true)
{
// For every ping object
foreach (Ping pinger in pings)
{
// Set the appropriate UI element properties
// Create initial control object
// Finds controls in which their name matches the string
Control? ctl = this.Controls.Find("greenBox" + counter, true).FirstOrDefault() as Control;
if (ctl != null)
{
ctl.Visible = false;
}
ctl = this.Controls.Find("orangeBox" + counter, true).FirstOrDefault() as Control;
if (ctl != null)
{
ctl.Visible = false;
}
ctl = this.Controls.Find("redBox" + counter, true).FirstOrDefault() as Control;
if (ctl != null)
{
ctl.Visible = true;
}
ctl = this.Controls.Find("status_Lbl" + counter, true).FirstOrDefault() as Control;
if (ctl != null)
{
ctl.Text = "Initiated...";
}
counter++;
}
// Take input from text box
count = Convert.ToInt32(pingSeconds_TxtBox.Text);
// Start operation
backgroundWorker1.RunWorkerAsync();
}
}
这是等待1000毫秒的方法,
public void wait(int milliseconds)
{
var timer1 = new System.Windows.Forms.Timer();
if (milliseconds == 0 || milliseconds < 0) return;
timer1.Interval = milliseconds;
timer1.Enabled = true;
timer1.Start();
timer1.Tick += (s, e) =>
{
timer1.Enabled = false;
timer1.Stop();
};
while (timer1.Enabled)
{
Application.DoEvents();
}
}
它循环的次数似乎是随机的,我只是对其进行了测试删除线后,以防.doevents();线正在干扰背景工作者。
while (timer1.Enabled)
{
Application.DoEvents();
}
用count = 10
像往常一样运行它,这是两次,并且第一次运行一次,第二次跑了7次。
任何帮助都将不胜感激
答案 删除了背景工人并实施了async/等待
- Charlieface提供的答案
I have a program that sends a ping object, it sends out the ping request, repeats for each ping object (there's 8), waits 1000ms, and then repeats this for however many seconds the user specifies.
When telling the program to run for a low amount of time 2-3 seconds, the loop works as expected. Outputting the amount of successful pings successfully (if it ran for 2 seconds then I would expect each ping object to have 2 successful pings which they do)
An example of the unexpected behaviour I'm receiving is this, I set the amount of seconds to run as 10, so it should loop through each of the 8 ping objects, wait one second, and repeat this for count > 10
I am debugging and the loop works as expected but then suddenly exits after around 6 'seconds'. I can see that count = 10
, and i is 6
but then the worker exits and the RunWorkerCompleted
method is called.
I can think of maybe its a problem with threading(?) but I am unsure.
Here is the background worker DoWork
method:
private async void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
// Create background worker
BackgroundWorker worker = (BackgroundWorker)sender;
// Write to log file
await file.WriteAsync("Starting job...\n");
await file.WriteAsync("Requested amount of pings: " + count + "\n");
// Create date object for logs
DateTime localDate = DateTime.Now;
for (int i = 0; i < count; i++)
{
// Create ping objects
System.Net.NetworkInformation.Ping pinger = new System.Net.NetworkInformation.Ping();
PingReply pingReply;
foreach (Ping pingObj in pings)
{
try
{
pingReply = pinger.Send(pingObj.IpAddress);
// Write log file
await file.WriteLineAsync(localDate.TimeOfDay + " | Friendly Name " + pingObj.FriendlyName + " | Ping: " + pingReply.Address + " | Status " + pingReply.Status + " | Time: " + pingReply.RoundtripTime);
if (pingReply.Status.ToString().Contains("Success"))
{
pingObj.SuccessfulPings += 1;
}
else // Unsuccessful ping has been sent
{
pingObj.FailedPings += 1;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
wait(1000);
}
}
catch (Exception a)
{
Debug.WriteLine(a.ToString());
}
}
Here's how I begin the worker, with a button:
private void Ping_Btn_Click(object sender, EventArgs e)
{
int counter = 1;
if (backgroundWorker1.IsBusy != true)
{
// For every ping object
foreach (Ping pinger in pings)
{
// Set the appropriate UI element properties
// Create initial control object
// Finds controls in which their name matches the string
Control? ctl = this.Controls.Find("greenBox" + counter, true).FirstOrDefault() as Control;
if (ctl != null)
{
ctl.Visible = false;
}
ctl = this.Controls.Find("orangeBox" + counter, true).FirstOrDefault() as Control;
if (ctl != null)
{
ctl.Visible = false;
}
ctl = this.Controls.Find("redBox" + counter, true).FirstOrDefault() as Control;
if (ctl != null)
{
ctl.Visible = true;
}
ctl = this.Controls.Find("status_Lbl" + counter, true).FirstOrDefault() as Control;
if (ctl != null)
{
ctl.Text = "Initiated...";
}
counter++;
}
// Take input from text box
count = Convert.ToInt32(pingSeconds_TxtBox.Text);
// Start operation
backgroundWorker1.RunWorkerAsync();
}
}
Here is the method for waiting 1000 ms
public void wait(int milliseconds)
{
var timer1 = new System.Windows.Forms.Timer();
if (milliseconds == 0 || milliseconds < 0) return;
timer1.Interval = milliseconds;
timer1.Enabled = true;
timer1.Start();
timer1.Tick += (s, e) =>
{
timer1.Enabled = false;
timer1.Stop();
};
while (timer1.Enabled)
{
Application.DoEvents();
}
}
The amount of times it loops through seems to be random, I tested it just there after removing the lines just in case the .DoEvents(); line is interfering with the background worker.
while (timer1.Enabled)
{
Application.DoEvents();
}
Ran it as usual with count = 10
did this twice and the first time it ran through once, and the second time it ran through 7 times.
Any help would be appreciated
Answer
Removed background worker and implemented async/await
instead
- Answer provided by Charlieface
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您不能混合
async void
和backgroundworker.dowork
,因为一旦您击中第一个等待
,dowork 处理程序已向工人出现。
我建议您完全删除
backgroundworker
,只需使用等待
即可。示例代码似乎缺少信息:什么是
pings
count
和文件
?我试图猜测它是如何工作的,但是看来您正在为这些使用某种缓存字段,至少在file
的情况下)可能是不可接受的。You can't mix
async void
andBackgroundWorker.DoWork
, because as soon as you hit the firstawait
then theDoWork
handler appears to the worker that it has finished.I would advise you to remove the
BackgroundWorker
entirely, and just useawait
.There appears to be missing information from your sample code: what are
pings
count
andfile
? I have tried to guess how that works, but it looks like you are using some kind of cached field for these, which (at least in the case offile
) is probably inadvisable.