我定期进入我认为是parallel.ForEach循环中的竞争条件。我这样说是因为它总是挂在代码的那一部分上。
try
{
Parallel.ForEach(Directory.EnumerateFiles(directory, "*.tracex", SearchOption.TopDirectoryOnly), _po, (path, ls) =>
{
DebugFile file;
if (filterDate)
{
if (filterUser)
{
file = new DebugFile(path, startTime, endTime, user);
}
else file = new DebugFile(path, startTime, endTime);
}
else if (filterUser)
{
file = new DebugFile(path, user);
}
else file = new DebugFile(path);
if (!file.IsFiltered())
{
_files.Add(file);
}
Interlocked.Increment(ref _loadCount); // increment how many we've checked
if (_po.CancellationToken.IsCancellationRequested)
{
ls.Break();
}
});
}
catch (OperationCanceledException oce)
{
Debug.WriteLine(oce.ToString());
}
在我的_files对象中,我在调用Add方法时处理锁定。
public virtual void Add(T item)
{
_lock.EnterWriteLock();
try
{
_bindingList.Add(item);
}
finally
{
_lock.ExitWriteLock();
}
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, _bindingList.Count - 1));
}
任何想法我在这里做错了什么?它不会每次都挂起,只是间歇性地。此外,至少对我而言,第一次调用代码时不会发生这种情况。只有当我打电话一次,然后再次打电话,通常是第二次或第三次时,它才会发生。
谢谢!
更新 我意识到我正在使用自定义任务调度程序。当我删除它时,我不再看到挂起。我这样做了所以我可以自定义我运行的线程数。我的想法是,由于我主要通过网络读取文件,因此IO会减慢速度,因此我可以立即运行更多任务。以下是我构建调度程序的方法:
public class TaskSchedulerForSlowIO : TaskScheduler
{
/// <summary>
/// maximum number of tasks to run concurrently
/// </summary>
private int _maxConcurrencyLevel;
/// <summary>
/// lock for reading tasks array
/// </summary>
private ReaderWriterLockSlim _listLock = new ReaderWriterLockSlim();
/// <summary>
/// list of tasks running
/// </summary>
private LinkedList<Task> _tasks = new LinkedList<Task>();
/// <summary>
/// Default constructor - This will increase threadpool limits if necessary
/// </summary>
public TaskSchedulerForSlowIO()
: base()
{
_maxConcurrencyLevel = Environment.ProcessorCount * 10;
int workerThreads, ioThreads, minimumConcurrency;
minimumConcurrency = Environment.ProcessorCount * 2;
ThreadPool.GetMaxThreads(out workerThreads, out ioThreads);
if (workerThreads < _maxConcurrencyLevel)
{
if (ioThreads < _maxConcurrencyLevel)
{
ioThreads = _maxConcurrencyLevel;
}
ThreadPool.SetMaxThreads(_maxConcurrencyLevel, ioThreads);
}
ThreadPool.GetMinThreads(out workerThreads, out ioThreads);
if (workerThreads < minimumConcurrency)
{
if (ioThreads < minimumConcurrency)
{
ioThreads = minimumConcurrency;
}
ThreadPool.SetMinThreads(minimumConcurrency, ioThreads);
}
}
/// <summary>
/// Implementing TaskScheduler
/// </summary>
public override int MaximumConcurrencyLevel
{
get
{
return _maxConcurrencyLevel;
}
}
/// <summary>
/// Scheduler Implementation
/// </summary>
/// <returns>ScheduledTasks</returns>
protected override IEnumerable<Task> GetScheduledTasks()
{
Task[] tasks;
_listLock.EnterReadLock();
try
{
tasks = _tasks.ToArray();
}
finally
{
_listLock.ExitReadLock();
}
return tasks;
}
/// <summary>
/// Queues the specified task
/// </summary>
/// <param name="task">Task to queue</param>
protected override void QueueTask(Task task)
{
int count;
_listLock.EnterReadLock();
try
{
_tasks.AddLast(task);
count = _tasks.Count;
}
finally
{
_listLock.ExitReadLock();
}
if (count <= _maxConcurrencyLevel)
{
ThreadPool.UnsafeQueueUserWorkItem(ProcessTask, task);
}
}
/// <summary>
/// Scheduler Implementation
/// </summary>
/// <param name="task">Task to remove</param>
/// <returns>Success</returns>
protected override bool TryDequeue(Task task)
{
_listLock.EnterWriteLock();
try
{
return _tasks.Remove(task);
}
finally
{
_listLock.ExitWriteLock();
}
}
/// <summary>
/// Scheduled Implementation
/// </summary>
/// <param name="task">Task to execute</param>
/// <param name="taskWasPreviouslyQueued">Was the task previously queued</param>
/// <returns></returns>
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
//We're not going to inline slow IO
return false;
}
void ProcessTask(object o)
{
try
{
Task t = o as Task;
if (t != null)
{
if (base.TryExecuteTask(t))
{
if(!(t.IsCanceled || t.IsFaulted)) t.Wait();
TryDequeue(t);
}
}
}
catch(AggregateException a)
{
var e = a.Flatten();
foreach (Exception ex in e.InnerExceptions)
{
Debug.WriteLine(ex.ToString());
}
}
}
}
答案 0 :(得分:-1)
可能有很多原因。 例如
1)起源,因此filterUser
,filterDate
,IsFiltered()
的变异特征......在代码上看不清楚,这可能会导致问题。
2)通常,代码是不可扩展的。避免并行访问(读取)文件,因为IO设备(在我的情况下我假设的硬盘)不是并行读取设备,并且在简单的串行处理的情况下,您很可能会获得更差的性能。
Suggession:将线程亲和性设置为仅2个线程/核心(我再次假设你有更多),并调试,看看会发生什么。很可能你会达到冲突加剧的程度。