TripOptimizerImpl::OptimizeTripAsync方法调用TripOptimizer::OptimizeTrip方法作为异步操作的一部分,TripOptimizer::OptimizeTrip方法调用TripOptimizer::CreateGraph创建出行路线的图像,每个位置由一个节点表示,并且每个节点对由棱边相连,一个节点包含了一个位置的名称,经纬度等信息,而棱边包含两点间的距离,相关代码如下。
//创建表示出游地形的图像
void TripOptimizerImpl::CreateGraph(
const vector<wstring>& waypoints,
vector<shared_ptr<Node>>& nodes,
vector<shared_ptr<Edge>>& edges)
{
// 创建一个节点对象,每个对象包含的字符串代表一个位置
for_each(begin(waypoints), end(waypoints), [&nodes](const wstring& waypoint) {
// 对集合添加节点对象
nodes.push_back(make_shared<Node>(waypoint));
});
//
// 创建棱边,形成节点全连接的图像
//
for (auto iter = begin(nodes); iter != end(nodes); ++iter) {
auto node1 = *iter;
for_each(iter + 1, end(nodes), [this, &node1, &edges](shared_ptr<Node> node2) {
//创建棱边对
edges.push_back(make_shared<Edge>(node1, node2));
});
}
}
TripOptimizerImpl::OptimizeTrip方法在3个阶段执行线路优化操作。第一个阶段中,这个方法获取Bing Maps传来的位置信息数据;第二个阶段中,这个方法获取路线中每两点间,可能的路由信息;第三阶段中,这个方法执行线路优化算法。任务的Continuation(Continuation意为在每件事完成之后还要做的事)使得任务完成后可接着运行一个或多个任务。但注意,由于Continuation在后台的运行,需要存储在这些任务中共享的变量,从而使任务可以稍后就能访问它们。TripOptimizerImpl类定义了OptimizeTripParams结构体,这个结构体保留着对TripOptimizer::OptimizeTripAsync方法,和任务间共享变量的输入,有关代码如下。
// 包含出行优化整个过程中,所使用的变量
// 创建这个结构体为的是,使通用参数轻松在连续的任务间传递。
struct OptimizeTripParams
{
//
// 对OptimizeTripAsync的输入
std::vector<std::wstring> Waypoints;
std::wstring TravelMode;
std::wstring Optimize;
std::wstring BingMapsKey;
double Alpha;
double Beta;
double Rho;
unsigned long Iterations;
bool Parallel;
//
// 定时器变量
// 以下时间作为进度信息发送出去
// 总体时间
ULONGLONG TotalTime;
// 总体时间和所花费的HTTP请求时间
ULONGLONG HttpTime;
// 执行优化算法花费的时间
ULONGLONG SimulationTime;
// 位置图像
// 节点对象的集合,每个位置一个节点
std::vector<std::shared_ptr<AntSystem::Node>> Nodes;
// 棱边对象的集合,有(n * (n - 1) / 2)个棱边,其中n代表节点个数
std::vector<std::shared_ptr<AntSystem::Edge>> Edges;
// 对目前批处理挂起的HTTP请求数量
long RequestsPending;
// 保留在线路优化过程的第一阶段未解决的位置
Concurrency::concurrent_vector<std::shared_ptr<AntSystem::Node>> UnresolvedLocations;
};
通过使用一个std::shared_ptr对象,TripOptimizer::OptimizeTripAsync方法创建一个OptimizeTripParams结构体,并将其传递任务链中的每个Continuation,代码如下。
auto params = make_shared<OptimizeTripParams>();
for_each(begin(waypoints), end(waypoints), [params](String^ waypoint) {
params->Waypoints.push_back(waypoint->Data());
});
params->TravelMode = wstring(travelMode->Data());
params->Optimize = wstring(optimize->Data());
params->BingMapsKey = UriEncode(bingMapsKey->Data());
params->Alpha = alpha;
params->Beta = beta;
params->Rho = rho;
params->Iterations = iterations;
params->Parallel = parallel;
5)HTTP相关处理。C++组件定义了HttpRequest类处理HTTP请求,本类使用IXMLHTTPRequest2接口处理HTTP请求。IXMLHTTPRequest2接口只支持异步操作,为使调用函数更容易使用这些异步的操作,HttpRequest::StartDownload方法返回一个Concurrency::task<std::tuple<HRESULT, std::wstring>>对象,这个对象将状态码和HTTP响应作为一个字符串包含其中。
由于IXMLHTTPRequest2只支持异步操作,所以从HTTP服务器请求数据时,必须提供一个IXMLHTTPRequest2Callback对象。HttpRequest.cpp文件定义了HttpRequestCallback类,此类是从IXMLHTTPRequest2Callback继承来的,并实现其方法。
Concurrency::task_completion_event类是很重要的一部分,在其他异步任务完成时,它使得HttpReader类创建一个任务,这个类在将任务对象,还有通过回调函数完成的异步操作,组合在一起的时候很有用。当下载操作完成时,HttpRequestCallback::OnResponseReceived方法设置结束事件,代码如下。
m_completionEvent.set(make_tuple<HRESULT, wstring>(S_OK, ss.str()));
相应地,HttpRequestCallback::OnError方法在错误发生时设置结束事件,这种情况下,任务的输出结果会是错误代码和空字符串,代码如下。
m_completionEvent.set(make_tuple<HRESULT, wstring>(hrError, wstring()));
HttpRequestCallback类同样在下载任务取消时,设置结束事件,这种情况下,任务的输出结果会是S_OK和空字符串,代码如下。
m_completionEvent.set(make_tuple<HRESULT, wstring>(S_OK, wstring()));
HttpRequest::StartDownload函数打开异步请求,创建一个HttpRequestCallback对象,之后其创建一个task对象,在HttpRequestCallback对象的任务结束事件完成时就结束,代码如下。
// 开始指定URI的下载
task<tuple<HRESULT, wstring>> HttpRequest::StartDownload(
const wstring& method,
const wstring& uri,
cancellation_token cancellationToken)
{
// 创建一个IXMLHTTPRequest2对象
IXMLHTTPRequest2* xhr;
HRESULT hr = CoCreateInstance(
__uuidof(FreeThreadedXMLHTTP60),
nullptr,
CLSCTX_INPROC,
__uuidof(IXMLHTTPRequest2),
reinterpret_cast<void**>(&xhr));
SUCCEEDED(hr) ? 0 : throw hr;
// 创建回调函数
auto callback = new HttpRequestCallback(xhr, cancellationToken);
callback->AddRef();
// 打开并发送请求
hr = xhr->Open(method.c_str(), uri.c_str(), callback, nullptr, nullptr, nullptr, nullptr);
SUCCEEDED(hr) ? 0 : throw hr;
hr = xhr->Send(nullptr, 0);
SUCCEEDED(hr) ? 0 : throw hr;
// 操作结束时返回一个完成的任务
task<tuple<HRESULT, wstring>> result(callback->m_completionEvent);
return result.then([callback](task<tuple<HRESULT, wstring>> previousTask) {
callback->Release();
return previousTask;
});
}