当前位置: 移动技术网 > IT编程>开发语言>.net > .NET中并行开发优化

.NET中并行开发优化

2019年06月22日  | 移动技术网IT编程  | 我要评论

蜻蜓图片,上海人才网聚派,绿游网

让我们考虑一个简单的编程挑战:对大数组中的所有元素求和。现在可以通过使用并行性来轻松优化这一点,特别是对于具有数千或数百万个元素的巨大阵列,还有理由认为,并行处理时间应该与常规时间除以cpu核心数一样多。事实证明,这一壮举并不容易实现。我将向您展示几种并行执行此操作的方法,它们如何改善或降低性能以及以某种方式影响性能的所有细节。

简单的循环方法

private const int items = 500000;
private int[] arr = null;

public arrayc()
{
    arr = new int[items];
    var rnd = new random();
    for (int i = 0; i < items; i++)
    {
        arr[i] = rnd.next(1000);
    }
}

public long forlocalarr()
{
    long total = 0;
    for (int i = 0; i < items; i++)
    {
        total += int.parse(arr[i].tostring());
    }

    return total;
}

public long foreachlocalarr()
{
    long total = 0;
    foreach (var item in arr)
    {
        total += int.parse(item.tostring());
    }

    return total;
}

只需要迭代循环就可以计算出结果,超级简单,这里没有用直接相加求出结果,原因是直接求出结果,发现每次基本的运行都比并行快,但是实际上,并行处理没有那么简单,所以这里的加法就简单的处理下total += int.parse(arr[i].tostring())。现在,让我们尝试用并行性来打败数组迭代吧。

首次尝试

private object _lock = new object();

public long threadpoolwithlock()
{
    long total = 0;
    int threads = 8;
    var partsize = items / threads;
    task[] tasks = new task[threads];
    for (int ithread = 0; ithread < threads; ithread++)
    {
        var localthread = ithread;
        tasks[localthread] = task.run(() =>
        {
            for (int j = localthread * partsize; j < (localthread + 1) * partsize; j++)
            {
                lock (_lock)
                {
                    total += arr[j];
                }
            }
        });
    }

    task.waitall(tasks);
    return total;
}

请注意,您必须使用localthread变量来“保存”该ithread时间点的值。否则,它将是一个随着for循环前进而变化的捕获变量。当数据最后打的时候并行已经比普通的快了,但是发现快的不多,说明还可以优化

再次优化

public long threadpoolwithlock2()
{
    long total = 0;
    int threads = 8;
    var partsize = items / threads;
    task[] tasks = new task[threads];
    for (int ithread = 0; ithread < threads; ithread++)
    {
        var localthread = ithread;
        tasks[localthread] = task.run(() =>
        {
            long temp = 0;
            for (int j = localthread * partsize; j < (localthread + 1) * partsize; j++)
            {
                temp += int.parse(arr[j].tostring());
            }

            lock (_lock)
            {
                total += temp;
            }
        });
    }

    task.waitall(tasks);
    return total;
}

增加设置临时变量,减少lock次数,发现运行效果已经有质的提高,提高了几倍。忽然想起,有个parallel.for的方法,研究性能是否可以更快。

parallel.for优化

public long parallelforwithlock()
{
    long total = 0;
    int parts = 8;
    int partsize = items / parts;
    var parallel = parallel.for(0, parts, new paralleloptions(), (iter) =>
    {
        long temp = 0;
        for (int j = iter * partsize; j < (iter + 1) * partsize; j++)
        {
            temp += int.parse(arr[j].tostring());
        }

        lock (_lock)
        {
            total += temp;
        }
    });
    return total;
}

运行结果比普通迭代快,但是没有threadpool快,但是觉得parallel.for还可以继续优化,也许可以更快

parallel.for继续优化

public long parallelforwithlock2()
{
    long total = 0;
    int parts = 8;
    int partsize = items / parts;
    var parallel = parallel.for(0, parts,
        localinit: () => 0l, // initializes the "localtotal"
        body: (iter, state, localtotal) =>
        {
            for (int j = iter * partsize; j < (iter + 1) * partsize; j++)
            {
                localtotal += int.parse(arr[j].tostring());
            }

            return localtotal;
        },
        localfinally: (localtotal) => { total += localtotal; });
    return total;
}

运行效果已经很快,和threadpool优化过的差不多,有些时候更快

结论和总结

并行化优化肯定可以提高性能,但是这取决于很多因素,每个案例都应该进行测量和检查。
当各种线程需要通过某种锁定机制相互依赖时,性能会显着降低。

50万数据运行结果

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网