我想使以下代码线程安全。不幸的是,我尝试在此代码中的各个级别锁定但没有成功。我似乎能够实现线程安全的唯一实例是在整个循环周围放置一个锁,这有效地使Parallel.ForEach不比使用foreach更快(甚至可能更慢)。代码相对/几乎安全,没有锁定。它似乎只显示了geneTokens.Value [-1]键和gtCandidates.Value [-1]键总和的大小差异,大约每20次左右执行一次。
我意识到Dictionary不是线程安全的。但是,我不能将此特定对象更改为ConcurrentDictionary而不会在下游遇到重大性能影响。我宁愿用常规foreach运行这部分代码而不是更改该特定对象。但是,我使用ConcurrentDictionary来保存单个Dictionary对象。我也尝试过这个改变,但它并没有解决我的种族问题。
以下是我的班级变量:
//Holds all tokens derived from each sequence chunk
public static ConcurrentBag<sequenceItem> tokenBag =
new ConcurrentBag<sequenceItem>();
public BlockingCollection<sequenceItem> sequenceTokens = new
BlockingCollection<sequenceItem>(tokenBag);
public ConcurrentDictionary<string, int> categories = new
ConcurrentDictionary<string, int>();
public ConcurrentDictionary<int, Dictionary<int, int>> gtStartingFrequencies = new
ConcurrentDictionary<int, Dictionary<int, int>>();
public ConcurrentDictionary<string, Dictionary<int, int>> gtCandidates = new
ConcurrentDictionary<string, Dictionary<int, int>>();
public ConcurrentDictionary<string, Dictionary<int, int>> geneTokens = new
ConcurrentDictionary<string, Dictionary<int, int>>();
这是Parallel.ForEach:
Parallel.ForEach(sequenceTokens.GetConsumingEnumerable(), seqToken =>
{
lock (locker)
{
//Check to see if the Sequence Token is a Gene Token
Dictionary<int, int> geneTokenFreqs;
if (geneTokens.TryGetValue(seqToken.text, out geneTokenFreqs))
{ //The Sequence Token is a Gene Token
*****************Race Issue Seems To Occur Here****************************
//Increment or create category frequencies for each category provided
int frequency;
foreach (int category in seqToken.categories)
{
if (geneTokenFreqs.TryGetValue(category, out frequency))
{ //increment the category frequency, if it already exists
frequency++;
geneTokenFreqs[category] = frequency;
}
else
{ //Create the category frequency, if it does not exist
geneTokenFreqs.Add(category, 1);
}
}
//Update the frequencies total [-1] by the total # of categories incremented.
geneTokenFreqs[-1] += seqToken.categories.Length;
******************************************************************************
}
else
{ //The Sequence Token is NOT yet a Gene Token
//Check to see if the Sequence Token is a Gene Token Candidate yet
Dictionary<int, int> candidateTokenFreqs;
if (gtCandidates.TryGetValue(seqToken.text, out candidateTokenFreqs))
{
*****************Race Issue Seems To Occur Here****************************
//Increment or create category frequencies for each category provided
int frequency;
foreach (int category in seqToken.categories)
{
if (candidateTokenFreqs.TryGetValue(category, out frequency))
{ //increment the category frequency, if it already exists
frequency++;
candidateTokenFreqs[category] = frequency;
}
else
{ //Create the category frequency, if it does not exist
candidateTokenFreqs.Add(category, 1);
}
}
//Update the frequencies total [-1] by the total # of categories incremented.
candidateTokenFreqs[-1] += seqToken.categories.Length;
*****************************************************************************
//Only update the candidate sequence count once per sequence
if (candidateTokenFreqs[-3] != seqToken.sequenceId)
{
candidateTokenFreqs[-3] = seqToken.sequenceId;
candidateTokenFreqs[-2]++;
//Promote the Token Candidate to a Gene Token, if it has been found >=
//the user defined candidateThreshold
if (candidateTokenFreqs[-2] >= candidateThreshold)
{
Dictionary<int, int> deletedCandidate;
gtCandidates.TryRemove(seqToken.text, out deletedCandidate);
geneTokens.TryAdd(seqToken.text, candidateTokenFreqs);
}
}
}
else
{
//create a new token candidate frequencies dictionary by making
//a copy of the default dictionary from
gtCandidates.TryAdd(seqToken.text, new
Dictionary<int, int>(gtStartingFrequencies[seqToken.sequenceId]));
}
}
}
});
答案 0 :(得分:0)
显然,一个数据竞争来自于某些线程将在此处添加项目:
geneTokens.TryAdd(seqToken.text, candidateTokenFreqs);
其他人将在这里阅读:
if (geneTokens.TryGetValue(seqToken.text, out geneTokenFreqs))
答案 1 :(得分:-1)
我如何在我的项目中使用Concurrent Dictionary:
我在字典中放置一个标志,并从另一个线程检查,如果有或没有标志。如果旗帜存在,我会相应地完成我的任务..
为此我正在做的是:
1)声明并发字典 2)使用TryADD方法添加标志 3)尝试使用TryGet Methid检索单位。
1)声明
Dim cd As ConcurrentDictionary(Of Integer, [String]) = New ConcurrentDictionary(Of Integer, String)()
2)添加
If cd.TryAdd(1, "uno") Then
Console.WriteLine("CD.TryAdd() succeeded when it should have failed")
numFailures += 1
End If
3)检索
If cd.TryGetValue(1, "uno") Then
Console.WriteLine("CD.TryAdd() succeeded when it should have failed")
numFailures += 1
End If