c# – 线程导致GUI冻结

前端之家收集整理的这篇文章主要介绍了c# – 线程导致GUI冻结前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
所以我不是最熟悉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的速度,但是你的代码中应该做一些事情来使它更好地全面.如果问题仍然存在,那么找出问题要容易得多.

>创建Thread对象很昂贵.这就是为什么在C#中添加新类以更好地处理多线程的原因.现在您可以访问Task类或Parallel类(如下所述).
>从评论来看,你同时运行了很多线程.虽然运行它们不应该是一个问题,但如果你正在做的是激活WebRequests(除非你有一个很棒的网络),你实际上并没有多少使用它们.确实使用多个线程,但限制其数量.
>当您想在后台执行特定操作时,任务很棒.但是当你想在后台重复一个特定数据集的单个操作时…为什么不使用System.Threading.Tasks.Parallel类?具体来说,Parallel.ForEach(您可以在其中指定代理列表作为参数).此方法还允许您使用ParallelOptions设置在任何给定时刻应该同时运行的线程数.
>另一种代码编写方法是使用.NET 4.5中提供的async和await关键字.在这种情况下,你的GUI(按下按钮?)应该调用异步方法.
>使用Interlocked.Increment或Interlocked.Add等线程安全方法增加/减少多个线程可用的计数器.另外,请考虑您可以将代理列表更改为ConcurrentDictionary< string,bool> (其中bool表示代理是否有效)并且无需担心设置值,因为每个线程只能访问字典中自己的条目.例如,您可以使用LINQ:dictionary.Where(q => q.Value).Count()轻松地对总计进行排队,以获取工作代理的数量.当然还有其他类可用,具体取决于你想要解决的问题 – 也许是Queue(或ConcurrentQueue)?
>你的锁不应该真正起作用……因为它似乎是偶然的,而不是你的代码中的设计(感谢Luaan的评论).但你真的不应该这样做.请查阅MSDN documentation锁定以更好地了解它的工作原理.在MSDN示例中创建的对象不仅仅用于show.
>您还可以使用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;
        }
    }
原文链接:https://www.f2er.com/csharp/243155.html

猜你在找的C#相关文章