我有一个场景,我有多个线程添加到队列和多个线程从同一队列读取.如果队列达到特定大小,则填充队列的所有线程将在添加时被阻止,直到从队列中删除项目为止.
下面的解决方案就是我现在正在使用的问题,我的问题是:如何改进?是否有一个对象已经在我应该使用的BCL中启用此行为?
internal class BlockingCollection<T> : CollectionBase, IEnumerable
{
//todo: might be worth changing this into a proper QUEUE
private AutoResetEvent _FullEvent = new AutoResetEvent(false);
internal T this[int i]
{
get { return (T) List[i]; }
}
private int _MaxSize;
internal int MaxSize
{
get { return _MaxSize; }
set
{
_MaxSize = value;
checkSize();
}
}
internal BlockingCollection(int maxSize)
{
MaxSize = maxSize;
}
internal void Add(T item)
{
Trace.WriteLine(string.Format("BlockingCollection add waiting: {0}", Thread.CurrentThread.ManagedThreadId));
_FullEvent.WaitOne();
List.Add(item);
Trace.WriteLine(string.Format("BlockingCollection …Run Code Online (Sandbox Code Playgroud) 我有一些使用SqlConnection创建临时表(例如#Foo)的C#代码,调用存储过程来填充那些临时表并将结果返回给C#客户端,使用c#对这些结果执行复杂计算,并使用计算结果更新之前创建的临时表之一.
由于整个过程中使用的临时表,我们必须只有一个SqlConnection.
我发现了使用计算结果更新临时表时的性能瓶颈.此代码已经对更新进行批处理,以防止C#客户端内存不足.每批计算数据通过SqlCommand.ExecuteNonQuery发送到存储过程,然后sproc会更新临时表.代码将大部分时间花在对ExecuteNonQuery的调用上.
因此,我将其更改为BeginExecuteNonQuery,以及在线程上等待并调用EndExecuteNonQuery的代码.这提高了性能约三分之一,但我担心使用相同的SqlConnection对SqlCommand.BeginExecuteNonQuery进行多次并发调用.
这样可以,还是会遇到线程问题?
很抱歉很长的解释.
MSDN文档声明:
BeginExecuteNonQuery方法立即返回,但在代码执行相应的EndExecuteNonQuery方法调用之前,它不能执行任何其他对同一SqlCommand对象启动同步或异步执行的调用.
这似乎意味着不同的SqlCommand对象可以在第一个SqlCommand完成之前调用BeginExecuteNonQuery.
以下是一些说明问题的代码:
private class SqlCommandData
{
public SqlCommand Command { get; set; }
public IAsyncResult AsyncResult { get; set; }
}
public static void TestMultipleConcurrentBeginExecuteNonQueryCalls(string baseConnectionString)
{
var connectionStringBuilder = new SqlConnectionStringBuilder(baseConnectionString)
{
MultipleActiveResultSets = true,
AsynchronousProcessing = true
};
using (var connection = new SqlConnection(connectionStringBuilder.ConnectionString))
{
connection.Open();
// ELIDED - code that uses connection to do various Sql work
SqlDataReader dataReader = null;
// in real code, this would be initialized …Run Code Online (Sandbox Code Playgroud) 我想弄清楚使用队列的最佳方法是什么.我有一个返回DataTable的进程.反过来,每个DataTable都与之前的DataTable合并.有一个问题,在最终的BulkCopy(OutOfMemory)之前要保留的记录太多.
所以,我已经确定我应该立即处理每个传入的DataTable.考虑一下ConcurrentQueue<T>......但我不知道该WriteQueuedData()方法如何知道将一个表出列并将其写入数据库.
例如:
public class TableTransporter
{
private ConcurrentQueue<DataTable> tableQueue = new ConcurrentQueue<DataTable>();
public TableTransporter()
{
tableQueue.OnItemQueued += new EventHandler(WriteQueuedData); // no events available
}
public void ExtractData()
{
DataTable table;
// perform data extraction
tableQueue.Enqueue(table);
}
private void WriteQueuedData(object sender, EventArgs e)
{
BulkCopy(e.Table);
}
}
Run Code Online (Sandbox Code Playgroud)
我的第一个问题是,除了我实际上没有订阅任何事件的事实,如果我ExtractData()异步调用这将是我需要的全部内容吗?第二,我是否缺少关于ConcurrentQueue<T>函数的方式以及需要某种形式的触发器与排队对象异步工作的东西?
更新
我刚刚派生出一个ConcurrentQueue<T>具有OnItemQueued事件处理程序的类.然后:
new public void Enqueue (DataTable Table)
{
base.Enqueue(Table);
OnTableQueued(new TableQueuedEventArgs(Table));
}
public void OnTableQueued(TableQueuedEventArgs table)
{
EventHandler<TableQueuedEventArgs> handler = TableQueued; …Run Code Online (Sandbox Code Playgroud) 我有一个类维护一个Dictionary缓存一些数据的私有实例.
该类使用a从多个线程写入字典ReaderWriterLockSlim.
我想在课外公开字典的值.
什么是线程安全的方法呢?
现在,我有以下内容:
public ReadOnlyCollection<MyClass> Values() {
using (sync.ReadLock())
return new ReadOnlyCollection<MyClass>(cache.Values.ToArray());
}
Run Code Online (Sandbox Code Playgroud)
有没有办法这样做而不需要多次复制集合?
我正在使用.Net 3.5(不是4.0)
我有异步执行作业,每隔几分钟,有时Windows服务执行和以前的工作还没有完成一个窗口服务,使用线程有排队的新的工作方式,如果前一个处理不当完成,以便它开始运行时第一份工作完成了吗?