【发布时间】:2015-01-21 15:54:44
【问题描述】:
我有一个类负责通过调用旧类来检索产品可用性。这个遗留类本身通过 BLOCKING 网络调用在内部收集产品数据。 请注意,我无法修改旧版 API 的代码。由于所有产品都是相互独立的,我希望在不创建任何不必要的线程的情况下并行收集信息,也不会阻塞在调用此遗留 API 时被阻塞的线程。有了这个背景,这里就是我的基础课程了。
class Product
{
public int ID { get; set; }
public int VendorID { get; set; }
public string Name { get; set; }
}
class ProductSearchResult
{
public int ID { get; set; }
public int AvailableQuantity { get; set; }
public DateTime ShipDate { get; set; }
public bool Success { get; set; }
public string Error { get; set; }
}
class ProductProcessor
{
List<Product> products;
private static readonly SemaphoreSlim mutex = new SemaphoreSlim(2);
CancellationTokenSource cts = new CancellationTokenSource();
public ProductProcessor()
{
products = new List<Product>()
{
new Product() { ID = 1, VendorID = 100, Name = "PC" },
new Product() { ID = 2, VendorID = 101, Name = "Tablet" },
new Product() { ID = 3, VendorID = 100, Name = "Laptop" },
new Product() { ID = 4, VendorID = 102, Name = "GPS" },
new Product() { ID = 5, VendorID = 107, Name = "Mars Rover" }
};
}
public async void Start()
{
Task<ProductSearchResult>[] tasks = new Task<ProductSearchResult>[products.Count];
Parallel.For(0, products.Count(), async i =>
{
tasks[i] = RetrieveProductAvailablity(products[i].ID, cts.Token);
});
Task<ProductSearchResult> results = await Task.WhenAny(tasks);
// Logic for waiting on indiviaul tasks and reporting results
}
private async Task<ProductSearchResult> RetrieveProductAvailablity(int productId, CancellationToken cancellationToken)
{
ProductSearchResult result = new ProductSearchResult();
result.ID = productId;
if (cancellationToken.IsCancellationRequested)
{
result.Success = false;
result.Error = "Cancelled.";
return result;
}
try
{
await mutex.WaitAsync();
if (cancellationToken.IsCancellationRequested)
{
result.Success = false;
result.Error = "Cancelled.";
return result;
}
LegacyApp app = new LegacyApp();
bool success = await Task.Run(() => app.RetrieveProductAvailability(productId));
if (success)
{
result.Success = success;
result.AvailableQuantity = app.AvailableQuantity;
result.ShipDate = app.ShipDate;
}
else
{
result.Success = false;
result.Error = app.Error;
}
}
finally
{
mutex.Release();
}
return result;
}
}
鉴于我正在尝试将异步封装在同步 API 上,我有两个问题。
- 通过使用 Parallel.For 并将 Legay API 调用包装在 Task.Run 中,我是否创建了任何不必要的线程,这些线程可以在不阻塞调用线程的情况下避免,因为我们将在 UI 中使用此代码。
- 这段代码看起来仍然是线程安全的吗?
【问题讨论】:
标签: c# .net multithreading task-parallel-library async-await