ASP.NET后台线程性能指南(ASP.NET Background thread Performa

2019-09-18 23:20发布

我跑在我的asp.net web服务应用程序在后台线程。 该线程的责任是在特定的时间后,打的数据库和更新缓存的DataTable。 数据表有大约50万行。 在任务管理器,当我在看的过程中,第一次web开发服务器消耗的下一次围绕300,000K它去500,000K,有些时候它达到高于1,000,000K有时回落到500,000-600,000K。 正如我在我的本地机器上做的工作,以便在数据库中的数据并没有改变。 任何人都可以请指导我我在做什么错误的代码:

protected void Application_Start(object sender, EventArgs e)
    {
        Thread obj = new Thread(new ThreadStart(AddDataInCache));
        obj.IsBackground = true;
        obj.Start();
    }

private void AddDataInCache()
    {
        Int32 iCount = 0;
        while (true)
        {
            MyCollection _myCollection = new MyCollection();
            DataTable dtReferences = null;
            DataTable dtMainData = null;
            try
            {
                dtMainData = _myCollection.GetAllDataForCaching(ref dtReferences);

                HttpRuntime.Cache.Insert("DATA_ALL_CACHING", dtMainData, null,
                    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
                    CacheItemPriority.Default, null);

                HttpRuntime.Cache.Insert("DATA_REFERENCES_CACHING", dtReferences, null,
                    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
                    CacheItemPriority.NotRemovable, null
                    );
            }
            catch (Exception ex)
            {

            }
            finally
            {
                if (_myCollection != null)
                    _myCollection = null;

            }
            iCount++;
            Thread.Sleep(18000);
        }
    }

GetAllDataForCaching我得到一个SqlDataReader从我的数据访问层:

public DataTable GetAllDataForCaching(ref DataTable dReferenceTable)
{
      DataTable dtReturn = new DataTable();
      SqlDataReader dReader = null;
      try
      {
            dReader = SqlHelper.ExecuteReader(CommandType.StoredProcedure, "[GetDataForCaching]", null);
            if (dReader != null && dReader.HasRows)
            {
                  dtReturn.Load(dReader);
                  dReferenceTable = new DataTable();
                  if (dReader.HasRows)
                {
                    DataTable dtSchema = dReader.GetSchemaTable();
                    List<DataColumn> listCols = new List<DataColumn>();

                    if (dtSchema != null)
                    {
                        foreach (DataRow drow in dtSchema.Rows)
                        {
                            string columnName = System.Convert.ToString(drow["ColumnName"]);
                            DataColumn column = new DataColumn(columnName, (Type)(drow["DataType"]));
                            column.Unique = (bool)drow["IsUnique"];
                            column.AllowDBNull = (bool)drow["AllowDBNull"];
                            column.AutoIncrement = (bool)drow["IsAutoIncrement"];
                            listCols.Add(column);
                            dReferenceTable.Columns.Add(column);
                        }
                    }

                    while (dReader.Read())
                    {
                        DataRow dataRow = dReferenceTable.NewRow();
                        for (int i = 0; i < listCols.Count; i++)
                        {
                            dataRow[((DataColumn)listCols[i])] = dReader[i];
                        }
                        dReferenceTable.Rows.Add(dataRow);
                    }
                }
            }
      }
      finally
        {
            if (dReader != null)
            {
                if (dReader.IsClosed == false)
                    dReader.Close();
                dReader = null;
            }
        }
    return dtReturn;
}

我使用Visual Studio 2008。

Answer 1:

我会通过解决后续的问题开始:

......是,有时缓存返回null ...

这可能是因为它可能需要一些时间的后台线程来填充缓存。 当Application_Start火灾,你启动后台线程,然后Application_Start完成。 然后,应用程序可以转移到其他任务,比如处理页面。

如果页面的处理过程中,将尝试的初始运行之前访问缓存AddDataInCache已经完成,那么缓存将返回null。

关于内存消耗,我没有立即看到你如何能改善这种情况,除非你能够减少缓存数据表行的数量。

在第一次调用AddDataInCache ,缓存是空的开始。 然后你GetAllDataForCaching创建两个DataTable并用数据填充它们。 这使得处理AQUIRE存储器以存储在数据表中的数据。

在第二次和后续调用AddDataInCache ,如果缓存中已经包含所有这是在以前的运行获取的数据。 然后再创建两个新的数据表,并用数据填充它们。 这将导致内存消费,以便既保持高速缓存中已经存在的数据,并在第二次运行创建数据表的新数据止跌回升。 然后,一旦第二次运行已完成加载的数据你在第二轮获取的新数据缓存overwite先前存在的数据。

在他的观点,这是从第一次运行缓存中的数据就符合垃圾收集 。 但是,这并不意味着该内存会被立即回收。 当垃圾回收器恶有恶报,发现自己的数据表不再需要在内存中的内存将被回收。

需要注意的是,如果没有“活”的对象是抱着对它们的引用,从第一次运行时的缓存条目只会变得符合垃圾回收。 请确保你保持你的缓存使用短暂的。

虽然这一切是怎么回事,你的后台线程会很乐意去了解其业务刷新缓存。 因此,这有可能是垃圾收集器释放在第一次运行时获取的数据表前的记忆,导致内存消耗进一步增加发生第三缓存刷新。

因此,为了减少内存消耗,我想你会只需要减少的数据,你在缓存中存储(更少的行,列少)量。 增加高速缓存刷新之间的时间也可能会有所帮助。

最后,确保你不会保持高速缓存的对象在引用它们长寿的请求/应用程序还活着的旧版本。



Answer 2:

你会经常和一个计时器效率比具有线程睡眠这样。 计时器有更多的内存和CPU - 高效。



Answer 3:

我同意彼得和我会建议你使用System.Threading.Timer ,你可以找到这个下面的链接有用:

http://blogs.msdn.com/b/tmarq/archive/2007/07/21/an-ounce-of-prevention-using-system-threading-timer-in-an-asp-net-application.aspx



Answer 4:

我已经把下面的代码之前完成它Thread.Sleep(18000);

GC.Collect();
GC.WaitForPendingFinalizers();

这是保持内存控制为止。



Answer 5:

首先,你应该使用using (见IDisposable接口与数据库连接,命令,读写器等工作时)

其次Web缓存可以因为被清除池回收或重置IIS。 这就是为什么你不能依靠其在高速缓存中您的项目“永远”。 这是一种安全的方式来获取数据:

private DataTable GetDataWithReferences(out DataTable dtReferences)
{
    dtReferences = HttpRuntime.Cache["DATA_REFERENCES_CACHING"];
    DataTable dtMainData = HttpRuntime.Cache["DATA_ALL_CACHING"];
    if ( null == dtMainData )
    {
        dtMainData = _myCollection.GetAllDataForCaching(/*ref - why?*/out dtReferences);
        // cache insert
    }

    return dtMainData;
}


文章来源: ASP.NET Background thread Performance Guidance