- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我注意到 BackgroundWorkers 的一些奇怪行为以及它们正在触发的事件,其中事件似乎在一个线程中排队,而实际上并未使用 CPU。
基本上系统的设计是,基于用户交互,创建一个线程来发送 Web 请求以获取一些数据。根据结果,它可能会触发许多其他异步请求,对每个请求使用 BackgroundWorkers。我这样做是因为管理请求的代码使用锁来确保一次只发送一个请求(以避免向服务器发送多个同时请求的垃圾邮件,可能导致服务器忽略/阻止它们)。可能有更好的设计,我很想听听(我对 C#/Windows 窗体编程比较陌生,可以使用这些建议)。但是,无论设计更改如何,我都有兴趣了解导致我所看到的行为的原因。
我编写了一个相对简单的测试应用程序来演示这个问题。它基本上只是一个带有按钮和文本框的表单来显示结果(您可能可以不使用表单并在控制台上显示结果,但我这样做是为了复制我的实际应用程序所做的事情)。这是代码:
delegate void AddToLogCallback(string str);
private void AddToLog(string str)
{
if(textBox1.InvokeRequired)
{
AddToLogCallback callback = new AddToLogCallback(AddToLog);
Invoke(callback, new object[] { str });
}
else
{
textBox1.Text += DateTime.Now.ToString() + " " + str + System.Environment.NewLine;
textBox1.Select(textBox1.Text.Length, 0);
textBox1.ScrollToCaret();
}
}
private void Progress(object sender, ProgressChangedEventArgs args)
{
AddToLog(args.UserState.ToString());
}
private void Completed(object sender, RunWorkerCompletedEventArgs args)
{
AddToLog(args.Result.ToString());
}
private void DoWork(object sender, DoWorkEventArgs args)
{
BackgroundWorker worker = sender as BackgroundWorker;
lock (typeof(Form1)) // Ensure only a single request at a time
{
worker.ReportProgress(0, "Start");
Thread.Sleep(2000); // Simulate waiting on the request
worker.ReportProgress(50, "Middle");
Thread.Sleep(2000); // Simulate handling the response from the request
worker.ReportProgress(100, "End");
args.Result = args.Argument;
}
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(RunMe);
thread.Start();
}
private void RunMe()
{
for(int i=0; i < 20; i++)
{
AddToLog("Starting " + i.ToString());
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += DoWork;
worker.RunWorkerCompleted += Completed;
worker.ProgressChanged += Progress;
worker.RunWorkerAsync(i);
}
}
30/07/2009 2:43:22 PM Starting 0
30/07/2009 2:43:22 PM Starting 1
<snip>
30/07/2009 2:43:22 PM Starting 18
30/07/2009 2:43:22 PM Starting 19
30/07/2009 2:43:23 PM Start
30/07/2009 2:43:36 PM Middle
30/07/2009 2:43:36 PM End
30/07/2009 2:43:36 PM 0
30/07/2009 2:43:36 PM Start
30/07/2009 2:43:36 PM Middle
30/07/2009 2:43:36 PM End
30/07/2009 2:43:36 PM 1
30/07/2009 2:43:36 PM Start
30/07/2009 2:43:36 PM Middle
30/07/2009 2:43:36 PM End
30/07/2009 2:43:36 PM 8
30/07/2009 2:43:36 PM Start
30/07/2009 2:43:36 PM Middle
30/07/2009 2:43:38 PM 13
30/07/2009 2:43:38 PM End
30/07/2009 2:43:38 PM Start
30/07/2009 2:43:40 PM Middle
30/07/2009 2:43:42 PM 18
30/07/2009 2:43:42 PM Start
30/07/2009 2:43:42 PM End
30/07/2009 2:43:44 PM Middle
30/07/2009 2:43:46 PM End
30/07/2009 2:43:46 PM 2
30/07/2009 2:43:46 PM Start
30/07/2009 2:43:48 PM Middle
最佳答案
编辑:好的,我从头开始。这是一个简短但完整的控制台应用程序,它显示了问题。它记录消息的时间和它所在的线程:
using System;
using System.Threading;
using System.ComponentModel;
class Test
{
static void Main()
{
for(int i=0; i < 20; i++)
{
Log("Starting " + i);
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += DoWork;
worker.RunWorkerCompleted += Completed;
worker.ProgressChanged += Progress;
worker.RunWorkerAsync(i);
}
Console.ReadLine();
}
static void Log(object o)
{
Console.WriteLine("{0:HH:mm:ss.fff} : {1} : {2}",
DateTime.Now, Thread.CurrentThread.ManagedThreadId, o);
}
private static void Progress(object sender,
ProgressChangedEventArgs args)
{
Log(args.UserState);
}
private static void Completed(object sender,
RunWorkerCompletedEventArgs args)
{
Log(args.Result);
}
private static void DoWork(object sender, DoWorkEventArgs args)
{
BackgroundWorker worker = (BackgroundWorker) sender;
Log("Worker " + args.Argument + " started");
lock (typeof(Test)) // Ensure only a single request at a time
{
worker.ReportProgress(0, "Start");
Thread.Sleep(2000); // Simulate waiting on the request
worker.ReportProgress(50, "Middle");
Thread.Sleep(2000); // Simulate handling the response
worker.ReportProgress(100, "End");
args.Result = args.Argument;
}
}
}
14:51:35.323 : 1 : Starting 0
14:51:35.328 : 1 : Starting 1
14:51:35.330 : 1 : Starting 2
14:51:35.330 : 3 : Worker 0 started
14:51:35.334 : 4 : Worker 1 started
14:51:35.332 : 1 : Starting 3
14:51:35.337 : 1 : Starting 4
14:51:35.339 : 1 : Starting 5
14:51:35.340 : 1 : Starting 6
14:51:35.342 : 1 : Starting 7
14:51:35.343 : 1 : Starting 8
14:51:35.345 : 1 : Starting 9
14:51:35.346 : 1 : Starting 10
14:51:35.350 : 1 : Starting 11
14:51:35.351 : 1 : Starting 12
14:51:35.353 : 1 : Starting 13
14:51:35.355 : 1 : Starting 14
14:51:35.356 : 1 : Starting 15
14:51:35.358 : 1 : Starting 16
14:51:35.359 : 1 : Starting 17
14:51:35.361 : 1 : Starting 18
14:51:35.363 : 1 : Starting 19
14:51:36.334 : 5 : Worker 2 started
14:51:36.834 : 6 : Start
14:51:36.835 : 6 : Worker 3 started
14:51:37.334 : 7 : Worker 4 started
14:51:37.834 : 8 : Worker 5 started
14:51:38.334 : 9 : Worker 6 started
14:51:38.836 : 10 : Worker 7 started
14:51:39.334 : 3 : Worker 8 started
14:51:39.335 : 11 : Worker 9 started
14:51:40.335 : 12 : Worker 10 started
14:51:41.335 : 13 : Worker 11 started
14:51:42.335 : 14 : Worker 12 started
14:51:43.334 : 4 : Worker 13 started
14:51:44.335 : 15 : Worker 14 started
14:51:45.336 : 16 : Worker 15 started
14:51:46.335 : 17 : Worker 16 started
14:51:47.334 : 5 : Worker 17 started
14:51:48.335 : 18 : Worker 18 started
14:51:49.335 : 19 : Worker 19 started
14:51:50.335 : 20 : Middle
14:51:50.336 : 20 : End
14:51:50.337 : 20 : Start
14:51:50.339 : 20 : 0
14:51:50.341 : 20 : Middle
14:51:50.343 : 20 : End
14:51:50.344 : 20 : 1
14:51:50.346 : 20 : Start
14:51:50.348 : 20 : Middle
14:51:50.349 : 20 : End
14:51:50.351 : 20 : 2
14:51:50.352 : 20 : Start
14:51:50.354 : 20 : Middle
14:51:51.334 : 6 : End
14:51:51.335 : 6 : Start
14:51:51.334 : 20 : 3
14:51:53.334 : 20 : Middle
ThreadPool.SetMinThreads(500, 500)
然后即使在我的 Vista 盒子上,它也显示 worker 基本上都是一起开始的。
SetMinThreads
,您的盒子会发生什么情况? ?如果它在这种情况下有帮助,但对您的实际程序没有帮助,您能否制作一个类似的简短但完整的程序,表明即使使用
SetMinThreads
仍然是一个问题称呼?
ReportProgress
正在添加一个新的
ThreadPool
处理消息的任务......同时,您正忙于向线程池添加 20 个任务。现在关于线程池的事情是,如果没有足够的线程可以在请求到达时立即为它提供服务,那么池会在创建新线程之前等待半秒。这是为了避免为一组请求创建大量线程,如果您只是等待现有任务完成,这些请求可以很容易地在一个线程上处理。
ReportProgress
任务非常短——所以只要你有足够的线程来处理所有长时间运行的请求和一个短的请求,你就离开了,所有的消息都会很快通过。
ThreadPool.SetMaxThreads(50, 50);
关于multithreading - 创建 BackgroundWorkers 的线程似乎将 Completed 事件排队,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1204529/
我有一些基于 TThreads 的操作。现在我需要创建包含要完成的作业列表的线程,然后在前一个完成后立即触发每个线程...我应该如何编写它?我不能允许线程同时运行,因为可能有超过 10 000 个操作
我正在尝试使用 RxJS 来实现服务调用限制/排队。 例如,Google Maps 的 Geocoder API。假设我不希望它每秒被调用一次以上,但是我的应用程序的一个或多个部分可能会比这更频繁
我目前正在通过 freecodecamp 网站的 javascript 部分进行练习,我试图理解为什么特定的方法可以解决它。 function nextInLine(arr, item) { /
详情 我有一个带有动画的功能,当点击按钮时它会.append一个div到body。然后,div 将为其位置向下移动一点点设置动画。添加另一个时,所有 div 也会向下移动,因此它们不会重叠。 现在我们
我有一个正在发送 http 请求的应用程序,每次用户键入时都会返回一个 promise 。我让它每 500 毫秒去抖一次。有时我请求的 api 需要很长时间才能响应。例如,我对 a 发出搜索请求,该请
我一直在做一项作业,涉及实现包含空指针的队列,以便它们可以针对任何类型的数据进行泛化。我目前遇到一个奇怪的问题,虽然出队节点减少了列表的大小但没有返回我期望的节点。在出列操作中省略对 free() 的
我正在寻找概述“排队”的文章和引用资料(我在这里可能甚至没有使用正确的术语)。我希望通过 Redis、RabbitMQ、Celery、Kombu 以及我尚未了解的任何其他组件以及它们如何组合在一起的世
我使用 mbostock/queue用于排队一些异步操作。更多的是速率限制(UI 生成的事件很少,后端可以慢慢处理),并确保它们按顺序处理。我像这样使用它 function request(d, cb
我有我的 android 应用程序,它不是为离线工作而构建的,因此它依赖于网络连接/数据。 应用程序进行大量网络调用,使用新数据集更新 api。 我正在对其进行更改以使其脱机工作。 方法我想我将创建一
我想将 div 的内容更改 3 次,每次更改之间延迟 1 秒。delay() 在此代码中不起作用: $('#import-status-msg').html('Importing content ..
我需要根据存储在数据库中的时间线在 jQuery 中制作一系列动画。我将这些信息与函数名称(动画、幻灯片、淡入淡出...)、函数的选项/参数以及函数的回调一起存储。 我知道 jQuery 确实有 .q
我有以下方法 public async Task SomeMethod(parameters) { // here we execute some instructions which are
在我的 winforms 应用程序中,我有一个包含对象的队列: Queue _queuedRows = new Queue(); 对于每个对象,我必须启动一个单独的 backgroundwor
我有以下代码: for (int i = 1; i <= 500; i++) { BackgroundWorker t = new BackgroundWorker(); t.DoWo
我有一个 CAShapeLayer,我在其中设置了一个圆圈的动画。动画是先顺时针“撤消”圆圈,然后顺时针重画圆圈。有点像“旋转圈”。另一种说法是:将路径描边终点移动到起点,然后将起点移到终点。 动画本
所以,在前一段时间了解完成 block 之后,我非常喜欢使用完成 block 。我喜欢关闭,我喜欢将任何东西传递到任何我想要的地方的能力。 作为线程编程的新手,我一直远离 GCD 和 NSOperat
我有一些使用 FMDB sqllite 包装器 ( https://github.com/ccgus/fmdb ) 的代码,并且我希望从多个线程执行此代码。因此,我使用 FMDatabaseQueue
页面加载速度比预期慢。我用 Firebug 检查了时间线,我看到很多图像阻塞: http://i.imgur.com/tenTNVH.png 我想我做错了什么。 (我知道我这里有双 jquery,会消
我在使用 Alamofire 时遇到任务执行问题我使用了两次 Alamofire,第一次是收集数据( token ),然后我将使用它来发送我的 Post 请求。 我的两次请求之间的问题,数据的恢复是在
我想知道如何将选定的 YouTube 视频添加到临时播放列表/播放队列中? 我有一个选项,用户必须选择要包含在播放队列中的所有视频。 Click on the ADD icon (black back
我是一名优秀的程序员,十分优秀!