使用 TaskFactory.StartNew 内部循环:状态对象不起作用
本文关键字:状态 对象 不起作用 循环 TaskFactory StartNew 内部 使用 | 更新日期: 2023-09-27 18:31:19
首先我初始化搜索上下文列表:
var searchContexts = new List<SearchContext>();
for (byte pageNumber = 1; pageNumber < 6; pageNumber++)
{
var searchContext = GetSearchContext(context, vendor, workRequest, pageNumber);
searchContexts.Add(searchContext);
}
其中 SearchContext 定义如下:
public class SamoSearchContext
{
public WorkRequest WorkRequest
{ get; set; }
public Vendor Vendor
{ get; set; }
public WorkResponse WorkResponse
{ get; set; }
public byte PageNumber
{ get; set; }
}
然后为每个搜索上下文启动新线程:
var tasks = new Task[taskCount];
var taskScheduler = TaskScheduler.Default;
var index = 0;
foreach (var searchContext in searchContexts)
{
var ssc = searchContext;
tasks[index] = Task.Factory.StartNew((obj) => SendSearchRequest(ssc, token),
ssc, token, TaskCreationOptions.AttachedToParent, taskScheduler);
index++;
}
SendSearchRequest() 方法调用外部服务以获取下一个搜索结果页面(按页码)。以下是实现:
private void SendSearchRequest(SamoSearchContext context, CancellationToken token)
{
if (token.IsCancellationRequested)
return;
var workRequest = context.WorkRequest;
workRequest.@params.PRICE_PAGE = context.PageNumber;
context.WorkResponse = ServiceClient.GetWorkResponse<WorkRequest, WorkResponse>(ServiceOperations.GetPrice, workRequest, context.Vendor.UniformCode, context.Vendor.ID);
}
但是在循环执行后读取日志,我看到 pageNumber 总是 = 4。
不明白出了什么问题?
问题是当我创建 SearchContext 列表时,我不谨慎地使用了 copy workRequest by 引用 (newSearchContext.WorkRequest = workRequest)。因此,列表中的所有搜索上下文都引用了一个 workRequest 实例。然后,在 SendRequest() 中,每次我更改PRICE_PAGE这个实例的字段时。所以它是一样的,有点奇怪,它总是 = 4,但不是从 1 到 5 的随机数。
但是,尽管如此,现在我为 WorkRequest 实现了 Clone() 扩展方法,该方法将对象逐个字段复制到新实例中。现在它起作用了。感谢大家的参与!