gpt4 book ai didi

c# - 线程导致 GUI 卡住

转载 作者:太空狗 更新时间:2023-10-29 21:21:56 29 4
gpt4 key购买 nike

所以我在 C# 编程语言方面并不是最有经验的,但是我一直在这里和那里制作一些测试应用程序。

我注意到,我为正在处理的应用程序创建的线程越多,我的 GUI 就越开始卡住。我不确定为什么会发生这种情况,我以前认为应用程序多线程的部分目的是避免 GUI 卡住。

如有解释,将不胜感激。

此外,这是我用来创建线程的代码:

private void runThreads(int amount, ThreadStart address)
{
for (int i = 0; i < amount; i++)
{
threadAmount += 1;
Thread currentThread = new Thread(address);
currentThread.Start();
}
}

这是线程运行的内容:

private void checkProxies()
{
while (started)
{
try
{
WebRequest request = WebRequest.Create("http://google.co.nz/");
request.Timeout = (int)timeoutCounter.Value * 1000;
request.Proxy = new WebProxy(proxies[proxyIndex]);
Thread.SetData(Thread.GetNamedDataSlot("currentProxy"), proxies[proxyIndex]);
if (proxyIndex != proxies.Length)
{
proxyIndex += 1;
}
else
{
started = false;
}
request.GetResponse();
workingProxies += 1;
}
catch (WebException)
{
deadProxies += 1;
}

lock ("threadAmount")
{
if (threadAmount > proxies.Length - proxyIndex)
{
threadAmount -= 1;
break;
}
}
}
}

最佳答案

虽然我不能告诉您为什么您的代码会减慢 GUI 的速度,但您应该在代码中做一些事情来全面改善它。如果问题仍然存在,那么查明问题应该容易得多。

  1. 正在创建 Thread对象是昂贵的。这就是在 C# 中添加新类以更好地处理多线程的原因。现在您可以访问 Task类或 Parallel类(如下所述)。
  2. 从评论来看,您同时运行了很多线程。虽然只是 运行它们应该不是问题,但如果您正在做的是触发 WebRequests,那么您并没有真正从中得到太多用处。 (除非你有一个很棒的网络)。当然可以使用多个线程,但要限制它们的数量。
  3. A Task当您想在后台执行特定操作时非常有用。但是当你想在后台对一组特定数据重复单个操作时......为什么不使用 System.Threading.Tasks.Parallel类(class)?具体来说,Parallel.ForEach (您可以在其中指定代理列表作为参数)。此方法还允许您使用 ParallelOptions 设置在任何给定时刻应该同时运行的线程数。 .
  4. 另一种编码方法是使用 asyncawait .NET 4.5 中可用的关键字。在这种情况下,您的 GUI(按下按钮?)应该调用 async方法。
  5. 使用线程安全的方法,例如 Interlocked.IncrementInterlocked.Add增加/减少多个线程可用的计数器。另外,请考虑将代理列表更改为 ConcurrentDictionary<string, bool> (其中 bool 指示代理是否工作)并设置值而不必担心,因为每个线程只会访问其自己在字典中的条目。您可以使用 LINQ 轻松地在末尾对总数进行排队:dictionary.Where(q => q.Value).Count()例如,获取工作代理的数量。当然也可以使用其他类(class),具体取决于您希望如何解决问题 - 也许是 Queue (或 ConcurrentQueue)?
  6. 你的 lock不应该真的工作......就像在你的代码中,它似乎是偶然的而不是设计的(感谢 Luaan 的评论)。但你真的不应该那样做。咨询MSDN documentationlock更好地了解它是如何工作的。 Object在 MSDN 示例中创建的不仅仅是为了展示。
  7. 您还可以使用 BeginGetResponse 使请求本身成为多线程的和 EndGetResponse方法。事实上,您可以将其与 Task 结合使用类以获得更简洁的代码(Task 类可以将 Begin/End 方法对转换为单个 Task 对象)。

所以,快速回顾一下 - 使用 Parallel用于多线程的类,并使用并发类来保持原样。

这是我写的一个简单示例:

    private ConcurrentDictionary<string, bool?> values = new ConcurrentDictionary<string, bool?>();

private async void Button_Click(object sender, RoutedEventArgs e)
{
var result = await CheckProxies();
label.Content = result.ToString();
}

async Task<int> CheckProxies()
{
//I don't actually HAVE a list of proxies, so I make up some data
for (int i = 0; i < 1000; i++)
values[Guid.NewGuid().ToString()] = null;
await Task.Factory.StartNew(() => Parallel.ForEach(values, new ParallelOptions() { MaxDegreeOfParallelism = 10 }, this.PeformOperation));
//note that with maxDegreeOfParallelism set to a high value (like 1000)
//then I'll get a TON of failed requests simply because I'm overloading the network
//either that or google thinks I'm DDOSing them... >_<
return values.Where(v => v.Value == true).Count();
}

void PeformOperation(KeyValuePair<string, bool?> kvp)
{
try
{
WebRequest request = WebRequest.Create("http://google.co.nz/");
request.Timeout = 100;
//I'm not actually setting up the proxy from kvp,
//because it's populated with bogus data
request.GetResponse();

values[kvp.Key] = true;
}
catch (WebException)
{
values[kvp.Key] = false;
}
}

关于c# - 线程导致 GUI 卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31903271/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com