锁定时将线程返回到ThreadPool

时间:2017-02-07 17:00:10

标签: asp.net-core locking threadpool xunit.net

当我像这样锁定ThreadPool上的线程时,线程被阻塞:

private static object _testServerLock = new object();
private static TestServer _testServer = null;

public TestServer GetServer()
{
  lock (_testServerLock)
  {
    if (_testServer == null)
    {
      _testServer = new TestServer(); // does some async stuff internally
    }
  }
  return _testServer;
}

如果我有更多的并发线程调用它,那么我在ThreadPool中有线程,所有这些线程都会等待锁定,而其他地方发生的异步代码无法继续,因为它正在等待一个免费线程ThreadPool。

所以我不想阻止该线程,我需要在等待时将其返回给ThreadPool。
还有其他一些锁定方法可以将等待的线程返回给ThreadPool吗?

2 个答案:

答案 0 :(得分:1)

在锁内部必须完成的任务都应该移动到一个任务中,该任务在测试完成之前启动,并在创建资源时启动。

每当测试想要获取任务创建的资源时,它都可以在访问资源之前使用await on creator-task进行阻止。因此,对资源的所有访问都在任务中,并且不能阻止池中的所有线程。

类似的东西:

private static object _testServerLock = new object();
private static TestServer _testServer = null;
private static Task _testTask = null;

private async Task<TestServer> CreateTestServerAsync()
{
  ...
}

// Constructor of the fixture
public TestFixture()
{
  // The lock here may be ok, because it's before all the async stuff
  // and it doesn't wait for something inside
  lock (_testServerLock)
  {
    if (_testTask == null)
    {
      _testTask = Task.Run(async () => {
        // it's better to expose the async nature of the call
        _testServer = await CreateTestServerAsync();
      });
      // or just, whatever works
      //_testTask = Task.Run(() => {
      //  _testServer = new TestServer();
      //});
    }
  }
}

public async Task<TestServer> GetServerAsync()
{
  await _testTask;
  return _testServer;
}

更新

您可以使用静态成员的初始化来删除锁定。

private static TestServer _testServer = null;
private static Task _testTask = Task.Run(async () => {
  _testServer = await CreateTestServerAsync();
});

private static async Task<TestServer> CreateTestServerAsync()
{
  ...
}

public TestFixture()
{
}

public async Task<TestServer> GetServerAsync()
{
  await _testTask;
  return _testServer;
}

答案 1 :(得分:0)

使用xUnit~1.7 +,你可以做的主要是让你的测试方法返回Task<T>,然后使用async / await这将限制你的硬阻塞/占用线程

xUnit 2.0 +具有并行执行和mechanism for controlling access to state to be shared among tests。但请注意,这基本上是通过一次在Test Class中运行一个测试并一次一个地给出 Class Fixture (这相当于通常发生的情况 - 每个类只运行一个测试方法)来实现的。在一个时间)。 (如果使用 Collection Fixture ,则集合中的所有测试类都会成为单个测试类。

最后,xUnit 2提供了用于控制是否的开关:

  • 程序集与其他[Assemblies]
  • 并行运行
  • 测试集合/测试类与其他人并行运行
  • 两个上一个

您应该能够通过不隐藏async所做的事情来管理您的问题,而是将其暴露给测试方法或通过IAsyncLifetime进行构建/拆除