Return 线程锁定到 ThreadPool
Return thread to ThreadPool on lock
当我像这样锁定 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;
}
如果调用此方法的并发线程多于线程池中的线程,所有这些线程最终都会等待锁定,而其他地方发生的异步代码无法继续,因为它正在等待中的空闲线程线程池。
所以我不想阻塞线程,我需要在等待时将它 return 到 ThreadPool。
有没有其他方法可以将 return 等待线程锁定到线程池?
使用 xUnit ~1.7+,你可以做的主要事情是让你的测试方法 return Task<T>
然后使用 async
/await
这将限制你的hard-blocking/occupation 个线程
xUnit 2.0 + 具有并行执行和 mechanism for controlling access to state to be shared among tests。但是请注意,这基本上是通过 运行一次在测试 Class 中进行一项测试并一次将 Class 夹具 提供给一个测试来运行的(这相当于通常发生的情况 - 每 class 运行 一次只有一个测试方法)。 (如果您使用 Collection Fixture,实际上集合中的所有测试 Class 都会变成一个测试 Class)。
最后,xUnit 2 提供开关来控制是否:
- 组件运行与其他[组件]
并行
- 测试 Collections/Test Classes 运行 与其他人并行
- 前两个
您应该能够通过不隐藏 async
ness 来管理您的问题,而是将其暴露给测试方法或通过 [=16 构建 up/teardown =]
任何必须在锁内完成的工作都应移至任务中,该任务在测试之前启动,并在创建资源时完成。
每当测试想要获取任务创建的资源时,它可以在访问资源之前在 creator-task 上使用 await 进行阻塞。所以对资源的所有访问都在任务中,不能阻塞池的所有线程。
类似于:
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;
}
当我像这样锁定 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;
}
如果调用此方法的并发线程多于线程池中的线程,所有这些线程最终都会等待锁定,而其他地方发生的异步代码无法继续,因为它正在等待中的空闲线程线程池。
所以我不想阻塞线程,我需要在等待时将它 return 到 ThreadPool。
有没有其他方法可以将 return 等待线程锁定到线程池?
使用 xUnit ~1.7+,你可以做的主要事情是让你的测试方法 return Task<T>
然后使用 async
/await
这将限制你的hard-blocking/occupation 个线程
xUnit 2.0 + 具有并行执行和 mechanism for controlling access to state to be shared among tests。但是请注意,这基本上是通过 运行一次在测试 Class 中进行一项测试并一次将 Class 夹具 提供给一个测试来运行的(这相当于通常发生的情况 - 每 class 运行 一次只有一个测试方法)。 (如果您使用 Collection Fixture,实际上集合中的所有测试 Class 都会变成一个测试 Class)。
最后,xUnit 2 提供开关来控制是否:
- 组件运行与其他[组件] 并行
- 测试 Collections/Test Classes 运行 与其他人并行
- 前两个
您应该能够通过不隐藏 async
ness 来管理您的问题,而是将其暴露给测试方法或通过 [=16 构建 up/teardown =]
任何必须在锁内完成的工作都应移至任务中,该任务在测试之前启动,并在创建资源时完成。
每当测试想要获取任务创建的资源时,它可以在访问资源之前在 creator-task 上使用 await 进行阻塞。所以对资源的所有访问都在任务中,不能阻塞池的所有线程。
类似于:
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;
}