DoubleBuffered虚拟模式DataGridView慢速滚动

时间:2018-04-09 22:28:43

标签: c# datagridview task

我正在异步/并发处理代理服务器列表,测试每个代理服务器的有效性。这些代理服务器显示在一个自定义用户控件中,该控件继承自DataGridView,并在其构造函数中将DoubleBuffered属性设置为true。此外,该DGV不受数据限制,而是使用虚拟模式和CellValueNeeded。

在我测试显示代理(ProxyTester.Start())有效性的方法中,我可以使用SemaphoreSlim对象控制并发度。当使用像10这样的小值初始化该信号量时,我可以滚动DGV并查看正在更新的数据并且它是平滑的。如果我将并发度增加到更大的数字(如100),这会增加吞吐量(耶!),我的DGV在滚动期间开始滞后。

除了我已经完成的将DoubleBuffered设置为True并使用虚拟模式之外,如何在滚动/处理列表的过程中减少延迟,同时还具有高度的并发性?

public partial class ExtendedDataGridView : DataGridView
{
    public ExtendedDataGridView()
    {
        //InitializeComponent();
        DoubleBuffered = true;
    }
}

public partial class DataGridViewForm : Form
{

    private List<Proxy> proxies = new List<Proxy>();

    public DataGridViewForm()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < 10000; i++)
        {
            proxies.Add(new Proxy("127.0.0." + RandomUtility.GetRandomInt(1, 5), 8888));
        }
        extendedDataGridView1.RowCount = proxies.Count;
    }


    private void button2_Click(object sender, EventArgs e)
    {
        var judges = new List<ProxyJudge>();
        judges.Add(new ProxyJudge("http://azenv.net"));
        Task.Run(async () => { await ProxyTester.Start(proxies, judges, maxConcurrency: 1); });
    }


    private void extendedDataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
    {
        if (proxies.Count > 0)
        {
            var proxy = proxies[e.RowIndex];
            switch (e.ColumnIndex)
            {
                case 0:
                    e.Value = proxy.IP;
                    break;
                case 1:
                    e.Value = proxy.IsValid;
                    break;
                default:
                    break;
            }
        }
    }
}

public class ProxyTester
{
    public async static Task Start(List<Proxy> proxies, List<ProxyJudge> judges, List<ProxyTest> tests = null, PauseOrCancelToken pct = null, int maxConcurrency = 100)
    {
        if (tests == null)
        {
            tests = new List<ProxyTest>();
        }

        //Get external IP to check if proxy is anonymous.
        var publicIp = await WebUtility.GetPublicIP();

        //Validate proxy judges.
        var tasks = new List<Task>();
        var semaphore = new SemaphoreSlim(maxConcurrency);

        foreach (var judge in judges)
        {
            tasks.Add(Task.Run(async () => {
                await semaphore.WaitAsync();
                judge.IsValid = await judge.TestValidityAsync();
                if (pct != null) { await pct.PauseOrCancelIfRequested(); }
                semaphore.Release();
            }));
        }

        await Task.WhenAll(tasks);

        var validJudges = from judge in judges
                            where judge.IsValid
                            select judge;

        if (validJudges.Count() == 0)
        {
            throw new Exception("No valid judges loaded.");
        }

        //Validate proxy tests.
        tasks.Clear();
        foreach (var test in tests)
        {
            tasks.Add(Task.Run(async () => {
                await semaphore.WaitAsync();
                test.IsValid = await test.TestValidityAsync();
                if (pct != null) { await pct.PauseOrCancelIfRequested(); }
                semaphore.Release();
            }));
        }

        await Task.WhenAll(tasks);

        var validTests = from test in tests
                            where test.IsValid
                            select test;

        //Test proxies with a random, valid proxy judge.  If valid, test with all valid proxy tests.
        tasks.Clear();

        var count = 0;
        foreach (var proxy in proxies)
        {
            tasks.Add(Task.Run(async () =>
            {
                await semaphore.WaitAsync();
                proxy.IsValid = await proxy.TestValidityAsync(validJudges.ElementAt(RandomUtility.GetRandomInt(0, validJudges.Count())));
                semaphore.Release();
                Interlocked.Increment(ref count);
                Console.WriteLine(count);
                if (proxy.IsValid)
                {
                    proxy.TestedSites.AddRange(validTests);
                    var childTasks = new List<Task>();
                    foreach (var test in validTests)
                    {
                        childTasks.Add(Task.Run(async () =>
                        {
                            await semaphore.WaitAsync();
                            proxy.TestedSites.ElementAt(proxy.TestedSites.IndexOf(test)).IsValid = await proxy.TestValidityAsync(test);
                            if (pct != null) { await pct.PauseOrCancelIfRequested(); }
                            semaphore.Release();
                        }));
                    }

                    await Task.WhenAll(childTasks);
                }
            }));
        }


        await Task.WhenAll(tasks);

    }
}

0 个答案:

没有答案