动态线程如何帮助解决我的性能问题

时间:2014-07-18 09:36:40

标签: c# asp.net

使用.NET Framework:3.5 Visual Studio 2008

我有一种在不同数据库上执行某些更新的方法。

现在我有一个'foreach循环',在其中调用执行数据库更新的函数。循环根据数据库的数量执行。 客户端服务器中可能有超过700个数据库。因此循环将执行700次,这将花费超过10个小时,这是一个很大的性能问题。

我们遇到的一个解决方案是动态线程创建。

例如:如果我们有100个数据库然后将它分成10个线程,带有1到10个数据库的Method将由thread1处理,接下来10到20个数据库调用将由线程2处理.....就像明智的那样100个数据库使用10个线程更新。

任何人都可以帮助我完成这项工作。如果您有任何其他合适的想法,请分享...

2 个答案:

答案 0 :(得分:0)

您可以使用工作线程池,如

public void DoWork()
{
    // queue in a loop
    System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(YourDatabaseWork));
}

private void YourDatabaseWork(Object state)
{
    // Insert code to perform a long task.
}

通过这种方式,您可以对您想要执行的每项工作进行排队(假设您不需要太多内存就可以一次完成所有工作)。有一些工作线程可用,所有其他线程将被放入队列中。因此,您应该能够立即“启动”所有线程,并且每次完成一个现有工作线程时,都会处理新的排队项目。

您可以在这里阅读更多内容: http://msdn.microsoft.com/en-us/library/h4732ks0.aspx

如果需要,如何使用输入参数,您可以在这里阅读: http://msdn.microsoft.com/en-us/library/4yd16hza.aspx

答案 1 :(得分:0)

您的问题最好通过异步解决。如果您的更新工作是IO绑定(通常是数据库更新命令),那么您的700个线程将只是坐在那里等待数据库更新在大多数时间内完成。解决方案是异步执行这些更新,然后线程池将拥有足够多的线程。

您可以同时启动所有更新,然后等待任务完成。如果您的更新更复杂并且涉及执行多个查询,请使每个查询异步执行并await结果。这是一个使用.net 4.5的简单示例:

public async Task UpdateDatabses(List<string> databses)
{
    List<Task> updateTasks = new List<Task>();

    foreach (var db in databses)
    {
        updateTasks.Add(UpdateDatabase(db));
    }

    // asynchronously wait for all the tasks to complete
    await Task.WhenAll(updateTasks);
}

public async Task UpdateDatabase(string databse)
{
    await /* Update the database */
}

<强>更新

对于.NET 3.5,您需要从Nuget安装 Task Parallel Librbary for .NET 3.5 包。我们需要Task.WhenAllTask.ConitnueWhenAll扩展方法,但我无法找到.NET 3.5的任何版本。所以我自己写了一个:

    public static class Extensions
    {
        /// <summary>
        /// Returns a task that completes when all the passed tasks are completed
        /// </summary>        
        public static Task WhenAll(IEnumerable<Task> tasks)
        {
            var tcs = new TaskCompletionSource<object>();

            var remainingTasks = tasks.ToList();
            int count = remainingTasks.Count();
            var exceptions = new List<Exception>();

            foreach (var task in remainingTasks)
            {
                task.ContinueWith(t =>
                {
                    if (Interlocked.Decrement(ref count) == 0)
                    {
                        foreach (var task1 in remainingTasks)
                        {
                            if (task1.IsFaulted)
                            {
                                exceptions.Add(task1.Exception);
                            }
                        }

                        if (exceptions.Any())
                        {
                            tcs.SetException(new AggregateException(exceptions));
                        }
                        else
                        {
                            tcs.SetResult(null);
                        }
                    }
                });
            }

            return tcs.Task;
        }
}

然后您应该能够将代码更改为以下内容:

    public Task UpdateDatabses(List<string> databses)
    {
        List<Task> updateTasks = new List<Task>();

        foreach (var db in databses)
        {
            updateTasks.Add(UpdateDatabase(db));
        }

        return Extensions.WhenAll(updateTasks);
    }

    public Task UpdateDatabase(string databse)
    {
        return null;  /* Update the database using a Task returninng asynchronous operation*/
    }