相关疑难解决方法(0)

不可变词典与词典Vs C5对F# - 表现

我们的应用程序使用了大量字典,这些字典具有不经常更改的多级查找.我们正在研究转换使用字典进行大量查找的一些关键代码,以使用替代结构 - 更快的查找,点亮内存/ gc.这让我们比较了各种可用的词典/库 -

Dictionary(System.Collections.Generics.Dictionary-SCGD) ,ImmutableDictionary,.C5.HashDictionaryFSharpMap

运行包含各种项目的以下程序 - 100,1000,10000,100000 - 表示词典在大多数范围内仍然是赢家.第一行表示集合中的项目.MS/Ticks将随机执行x查找所花费的时间(代码如下).

项目 - 100
SCGD - 0 MS - 50 Ticks
C5 - 1 MS - 1767 Ticks
Imm - 4 MS - 5951 Ticks
FS - 0 MS - 240 Ticks

项目 - 1000
SCGD - 0 MS - 230 Ticks
C5 - 0 MS - 496 Ticks
Imm - 0 MS - 1046 Ticks
FS - 1 MS - 1870 …

.net performance f# dictionary immutability

13
推荐指数
3
解决办法
5805
查看次数

使链接列表线程安全

我知道之前已经问过这个问题(我将继续研究),但我需要知道如何以线程安全的方式创建特定的链表功能.我当前的问题是我有一个循环遍历链表中所有元素的线程,另一个可能会在此列表的末尾添加更多元素.有时会发生这样的情况:一个线程尝试将另一个元素添加到列表中,而第一个元素正忙于迭代它(这会导致异常).

我想只是添加一个变量(布尔标志)来表示列表当前正在忙于迭代,但是我如何检查它并等待第二个线程(如果它等待,则可以,因为第一个线程运行很快).我能想到的唯一方法是通过使用while循环不断检查这个忙碌的标志.我意识到这是一个非常愚蠢的想法,因为它会导致CPU在没有任何用处的情况下努力工作.现在我在这里要求更好的见解.我已经阅读了关于锁等等,但它似乎与我的情况无关,但也许我错了?

与此同时,如果我找到解决方案,我将继续搜索互联网并发回.

编辑:让我知道我是否应该发布一些代码来清理,但我会尝试更清楚地解释它.

所以我有一个带有链表的类,其中包含需要处理的元素.我有一个线程通过函数调用遍历此列表(让我们称之为"processElements").我有第二个线程,以非确定的方式添加元素进行处理.但是,有时它会在processElements运行时尝试调用此addElement函数.这意味着当一个元素被第一个线程迭代时,它被添加到链表中.这是不可能的,并导致异常.希望这清除它.

我需要添加新元素的线程,直到processElements方法执行完毕.

  • 对任何绊倒这个问题的人.接受的答案将为您提供快速,简单的解决方案,但请查看下面的Brian Gideon的答案,以获得更全面的答案,这肯定会给您更多的见解!

c# multithreading

8
推荐指数
2
解决办法
7102
查看次数

锁定与比较和交换

我一直在阅读无锁技术,比如比较和交换,并利用Interlocked和SpinWait类来实现线程同步而不需要锁定.

我已经运行了一些我自己的测试,我只是有很多线程尝试将字符附加到字符串.我尝试使用常规locks和比较和交换.令人惊讶的是(至少对我而言),锁比使用CAS显示出更好的结果.

这是我的代码的CAS版本(基于).它遵循copy-> modify-> swap模式:

    private string _str = "";
    public void Append(char value)
    {
        var spin = new SpinWait();
        while (true)
        {
            var original = Interlocked.CompareExchange(ref _str, null, null);

            var newString = original + value;                
            if (Interlocked.CompareExchange(ref _str, newString, original) == original)
                break;
            spin.SpinOnce();
        }
    }
Run Code Online (Sandbox Code Playgroud)

更简单(也更有效)的锁定版本:

    private object lk = new object();
    public void AppendLock(char value)
    {
        lock (lk)
        {
            _str += value;
        }
    }
Run Code Online (Sandbox Code Playgroud)

如果我尝试添加50.000个字符,则CAS版本需要1.2秒,锁定版本需要700毫秒(平均值).对于100k字符,它们分别需要7秒和3.8秒.这是在四核(i5 2500k)上运行的.

我怀疑CAS显示这些结果的原因是因为它在最后一次"交换"步骤失败了.我是正确的.当我尝试添加50k字符(50k成功交换)时,我能够计算出70k(最佳情况)和近200k(最差情况)失败尝试之间的数量.最糟糕的情况是,每5次尝试中有4次失败.

所以我的问题是:

  1. 我错过了什么?CAS不应该给出更好的结果吗?好处在哪里?
  2. 究竟为什么CAS何时才是更好的选择?(我知道有人问过,但我找不到任何令人满意的答案,这也解释了我的具体情况).

我的理解是,采用CAS的解决方案尽管难以编码,但随着争用的增加,其规模要好得多,并且比锁具更好.在我的例子中,操作非常小且频繁,这意味着高争用和高频率.那么为什么我的测试显示不然呢?

我认为较长的操作会使情况更糟 - …

.net c# multithreading locking compare-and-swap

6
推荐指数
1
解决办法
5325
查看次数