&引用;固定";/&引用;“负载平衡”;C#线程池?

&引用;固定";/&引用;“负载平衡”;C#线程池?,c#,multithreading,wcf,C#,Multithreading,Wcf,我有一个第三方组件,它的启动成本很高。此组件不是线程安全的。所述组件托管在WCF服务内部(目前),因此。。。每次呼叫进入服务时,我都必须更新组件 我想做的是有一个由16个线程组成的池,每个线程都有自己的组件副本,并有一个机制来调用该方法,并将其分发到16个线程中的一个线程,然后返回值 简单的说: var response = threadPool.CallMethod(param1, param2); 在得到响应之前,调用阻塞是可以的,因为我需要响应才能继续 有什么建议吗?也许我想得太多了,一

我有一个第三方组件,它的启动成本很高。此组件不是线程安全的。所述组件托管在WCF服务内部(目前),因此。。。每次呼叫进入服务时,我都必须更新组件

我想做的是有一个由16个线程组成的池,每个线程都有自己的组件副本,并有一个机制来调用该方法,并将其分发到16个线程中的一个线程,然后返回值

简单的说:

var response = threadPool.CallMethod(param1, param2);
在得到响应之前,调用阻塞是可以的,因为我需要响应才能继续


有什么建议吗?也许我想得太多了,一个由16个线程提供服务的
ConcurrentQueue
可以完成这项工作,但是现在确定如何将方法返回值返回给调用者?

WCF已经使用线程池来管理它的资源,所以如果你在上面添加一层线程管理,那么它只会很糟糕。尽可能避免这样做,因为您将在服务调用中遇到争用

在您的情况下,我要做的就是使用一个单线程或静态线程,用您昂贵的对象初始化一次。此后,它将可用于线程池线程

这是假设您的对象在MTA线程上是正常的;我猜这是你的帖子,因为它听起来像是当前的工作,但只是缓慢


有一个问题是,创建了太多的对象,并且随着池变得太大,您使用了太多的内存。但是,在做其他事情之前,先看看实际情况是否如此。这是一个非常简单的策略,实施起来非常容易。如果你真的需要,只会变得更复杂。

首先,我同意@briantyler:
ThreadLocal
或thread静态字段可能是你想要的。你应该以这个为出发点,如果不符合你的需要考虑其他的选择。

一个复杂但灵活的替代方案是单例对象池。在最简单的形式中,您的池类型如下所示:

public sealed class ObjectPool<T>
{
    private readonly ConcurrentQueue<T> __objects = new ConcurrentQueue<T>();
    private readonly Func<T> __factory;

    public ObjectPool(Func<T> factory)
    {
        __factory = factory;
    }

    public T Get()
    {
        T obj;
        return __objects.TryDequeue(out obj) ? obj : __factory();
    }

    public void Return(T obj)
    {
        __objects.Enqueue(obj);
    }
}
用法:

// Get a pooled task or create a new one. The task may
// have already completed, in which case Result will
// be available immediately. If the task is still
// in flight, accessing its Result will block.
Task<MyComponent> task = pool.Get();

try
{
    MyComponent component = task.Result; // Alternatively you can "await task"

    // Do something with component.
}
finally
{
    pool.Return(task);
}

需要了解更多有关组件的信息。1) 它是COM组件吗?2) 您如何主持WCF服务?IIS?在Windows服务中?控制台应用程序?3) WCF服务的实例控制是什么?单身汉?每次通话?每次会话,在MickyD所说的,上面提到一个调用来创建一个新的组件实例并不能解决线程安全问题(我认为这实际上会使它更糟)。听起来,你真正需要的是一个对象池,而不是一个线程池。@ MickyD,我相信它是C++ C++中的一个C语言互操作包装器。WCF托管在IIS中。默认线程。@AWinkle。。。不尝试线程创建。尝试新建X个实例,并在应用程序的生命周期内保持它们的活动状态,并将调用分发给它们。是的,我想我要找的是一个对象池,而不是线程池。对象不是线程安全的。如果多个线程访问同一个实例,它将崩溃。当WCF服务创建和销毁线程时,ThreadLocal没有用。你实际测试过吗?很可能是这样,但这家伙认为它只是从线程池中提取线程:。他说不要使用线程静态来存储状态,但这里你不是在存储状态。是的,我认为这是一种方法。我只需要调整对象池,使其具有一组固定的X实例,而不是无限制地动态创建它们。@SledgeHammer,在这种情况下,您可以使用
BlockingCollection
作为对象池。如果您遇到了所有合并对象已被租出的情况,则下一个用户将阻塞“代码>收件人”/代码>直到其中一个实例被返回(通过<代码>添加< /代码>)。如果池实例计数超出期望值,则我还将考虑一个池:<代码>返回< /C> >丢弃返回的实例。这允许在绝对必要的情况下分配新实例,但会收集任何剩余实例,从而防止无限增长。不幸的是,这并没有达到预期效果:(.25在单线程环境中运行现在需要10秒。如果我创建一个单静态实例(未受保护),它下降到6秒,所以我有很高的期望——但是将实例从线程安全池中拉出来与创建一个新实例差不多。我用25秒将0到500毫秒缩短,所以我猜它不会真正产生差异,即使是在数百万的情况下,因为这不会扩展。
// Get a pooled task or create a new one. The task may
// have already completed, in which case Result will
// be available immediately. If the task is still
// in flight, accessing its Result will block.
Task<MyComponent> task = pool.Get();

try
{
    MyComponent component = task.Result; // Alternatively you can "await task"

    // Do something with component.
}
finally
{
    pool.Return(task);
}
public sealed class ObjectPool<T>
{
    private readonly Queue<T> __objects;

    public ObjectPool(IEnumerable<T> items)
    {
        __objects = new Queue<T>(items);
    }

    public T Get()
    {
        lock (__objects)
        {
            while (__objects.Count == 0) {
                Monitor.Wait(__objects);
            }

            return __objects.Dequeue();
        }
    }

    public void Return(T obj)
    {
        lock (__objects)
        {
            __objects.Enqueue(obj);

            Monitor.Pulse(__objects);
        }
    }
}