我有一个在IIS6中托管的WCF服务。该方法的重要部分如下所示:
public MyUser[] GetUsers(string appName, string[] names)
{
List<User> users = new List<User>();
foreach (string user in names)
{
MembershipUser mu = this.ADAMProvider.GetUser(user, false); //Unmanaged call to AzMan
if (mu != null)
{
users.Add(MyUser.CreateFrom(mu);
}
}
return users.ToArray();
}
当使用大量用户名(超过100个左右)调用此方法时,此方法的性能非常差。返回可能需要一分多钟。此外,如果多个客户端同时调用此方法,它将超时。我甚至看到它打倒了应用程序池。请注意,在循环中正在调用AzMan。 AzMan是非托管COM组件。
为了提高性能,我正在考虑采用多线程方法。 .NET 4不是一个选项,所以Parallel.For不是一个选项,但在3.5中做等效项是。
我的问题是会创建一堆线程(然后在返回之前等待所有线程)实际上会提高性能吗?在IIS6托管的WCF服务中执行此操作是否存在危险?
答案 0 :(得分:3)
首先,我已经指出COM组件可能是一个问题,具体取决于其公寓状态。单线程单元对象只能在一个线程中运行。在STA对象上有一个自动编组操作可以有效地序列化对它的所有调用,所以无论你怎么努力,可能都没有得到任何并行化。即使它是MTA对象,如果GetUser
方法不是设计为线程安全的,也可能存在问题。
但假设这不是问题 1 我会使用ThreadPool
而不是创建一堆线程来执行此操作。这可能是它的样子。
public MyUser[] GetUsers(string appName, string[] names)
{
int count = 1; // Holds the number of pending work items.
var finished = new ManualResetEvent(false); // Used to wait for all work items to complete.
var users = new List<User>();
foreach (string user in names)
{
Interlocked.Increment(ref count); // Indicate that we have another work item.
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
MembershipUser mu = this.ADAMProvider.GetUser(user, false);
if (mu != null)
{
lock (users)
{
users.Add(MyUser.CreateFrom(mu);
}
}
}
finally
{
// Signal the event if this is the last work item.
if (Interlocked.Decrement(ref count) == 0) finished.Set();
}
});
}
// Signal the event if this is the last work item.
if (Interlocked.Decrement(ref count) == 0) finished.Set();
// Wait for all work items to complete.
finished.WaitOne();
return users.ToArray();
}
关于我上面使用的模式的一个令人困惑的事情是它将主线程(排队工作的线程)视为另一个工作项。这就是你在循环结束时看到检查和信号代码的原因。没有它,Set
和WaitOne
次呼叫之间可能会出现非常微妙的竞争条件。
顺便说一下,我应该指出,作为Reactive Extensions下载的一部分,TPL在.NET 3.5中可用。
1 我怀疑我提到的两个问题之一将在现实中发挥作用。
答案 1 :(得分:2)
通常情况下,我会说这可能有所帮助 - 但是,这会引起关注:
此外,如果多个客户端同时调用此方法,它将超时。我甚至看到它打倒了应用程序池。请注意,在循环中,对AzMan的调用正在进行中。 AzMan是非托管COM组件。
这听起来像“AzMan”组件不是线程安全的。如果是这种情况,那么就不可能有效地多线程化这个例程,因为它将大部分时间花在这个例行程序中。
但是,如果该例程是线程安全的,并且不共享状态,则多线程可能提高性能。但是,它取决于许多其他问题,包括机器本身的工作量(如果所有核心都得到了很好的利用,它可能没有用),等等。