// 独立 Task 版本 // 首次检索 public async Task <NormalResult> Search( UseCollection useList, IsbnSplitter isbnSplitter, string strQueryWord, int nMax, string strFromStyle, string strMatchStyle, delegate_searchCompleted searchCompleted, delegate_presentCompleted presentCompleted) { _searching = true; try { List <Task> tasks = new List <Task>(); foreach (ZClientChannel channel in _channels) { if (_searching == false) { break; } if (channel.Enabled == false) { continue; } var task = Task.Factory.StartNew <NormalResult>( () => { return(SearchOne(channel, useList, isbnSplitter, strQueryWord, nMax, strFromStyle, strMatchStyle, searchCompleted, presentCompleted)); }); tasks.Add(task); } await Task.Run(() => { Task.WaitAll(tasks.ToArray(), TimeSpan.FromMinutes(1)); }).ConfigureAwait(false); return(new NormalResult()); } finally { _searching = false; } }
// 针对一个特定 Z30.50 服务器发起检索 async Task <NormalResult> SearchOne( ZClientChannel channel, UseCollection useList, IsbnSplitter isbnSplitter, string strQueryWord, int nMax, string strFromStyle, string strMatchStyle, delegate_searchCompleted searchCompleted, delegate_presentCompleted presentCompleted) { var ok = channel.Enter(); try { if (ok == false) { return(new NormalResult { Value = -1, ErrorInfo = "通道已被占用", ErrorCode = "channelInUse" }); } var _targetInfo = channel.TargetInfo; IsbnConvertInfo isbnconvertinfo = new IsbnConvertInfo { IsbnSplitter = isbnSplitter, ConvertStyle = (_targetInfo.IsbnAddHyphen == true ? "addhyphen," : "") + (_targetInfo.IsbnRemoveHyphen == true ? "removehyphen," : "") + (_targetInfo.IsbnForce10 == true ? "force10," : "") + (_targetInfo.IsbnForce13 == true ? "force13," : "") + (_targetInfo.IsbnWild == true ? "wild," : "") // TODO: + (_targetInfo.IssnForce8 == true ? "issnforce8," : "") }; string strQueryString = ""; { // 创建只包含一个检索词的简单 XML 检索式 // 注:这种 XML 检索式不是 Z39.50 函数库必需的。只是用它来方便构造 API 检索式的过程 string strQueryXml = BuildQueryXml(strQueryWord, strFromStyle); // 将 XML 检索式变化为 API 检索式 var result = ZClient.ConvertQueryString( useList, strQueryXml, isbnconvertinfo, out strQueryString); if (result.Value == -1) { searchCompleted?.Invoke(channel, new SearchResult(result)); var final_result = new NormalResult { Value = result.Value, ErrorInfo = result.ErrorInfo }; if (result.ErrorCode == "notFound") { final_result.ErrorCode = "useNotFound"; } return(final_result); } } REDO_SEARCH: { // return Value: // -1 出错 // 0 成功 // 1 调用前已经是初始化过的状态,本次没有进行初始化 // InitialResult result = _zclient.TryInitialize(_targetInfo).GetAwaiter().GetResult(); // InitialResult result = _zclient.TryInitialize(_targetInfo).Result; InitialResult result = await channel.ZClient.TryInitialize(_targetInfo); if (result.Value == -1) { searchCompleted?.Invoke(channel, new SearchResult(result)); // TODO: 是否继续向后检索其他 Z39.50 服务器? return(new NormalResult { Value = -1, ErrorInfo = "Initialize error: " + result.ErrorInfo }); } } // result.Value: // -1 error // 0 fail // 1 succeed // result.ResultCount: // 命中结果集内记录条数 (当 result.Value 为 1 时) SearchResult search_result = await channel.ZClient.Search( strQueryString, _targetInfo.DefaultQueryTermEncoding, _targetInfo.DbNames, _targetInfo.PreferredRecordSyntax, "default"); if (search_result.Value == -1 || search_result.Value == 0) { if (search_result.ErrorCode == "ConnectionAborted") { // 自动重试检索 goto REDO_SEARCH; } } searchCompleted?.Invoke(channel, search_result); channel._resultCount = search_result.ResultCount; if (search_result.Value == -1 || search_result.Value == 0 || search_result.ResultCount == 0) { return(new NormalResult()); // continue } var present_result = await _fetchRecords(channel, PresentBatchSize /*10*/); presentCompleted?.Invoke(channel, present_result); if (present_result.Value != -1) { channel._fetched += present_result.Records.Count; } return(new NormalResult()); } finally { channel.Exit(); } }
// 独立 Task 版本 // 首次检索 public async Task <NormalResult> SearchAsync( UseCollection useList, IsbnSplitter isbnSplitter, string strQueryWord, int nMax, string strFromStyle, string strMatchStyle, delegate_searchCompleted searchCompleted, delegate_presentCompleted presentCompleted) { _searching = true; try { List <Task <NormalResult> > tasks = new List <Task <NormalResult> >(); List <ZClientChannel> channels = new List <ZClientChannel>(); foreach (ZClientChannel channel in _channels) { if (_searching == false) { break; } if (channel.Enabled == false) { continue; } var task = Task.Factory.StartNew( async() => { return(await SearchOne(channel, useList, isbnSplitter, strQueryWord, nMax, strFromStyle, strMatchStyle, searchCompleted, presentCompleted)); }, new CancellationToken(), TaskCreationOptions.PreferFairness, TaskScheduler.Default); // tasks 和 channels 下标一一对应 tasks.Add(task.Unwrap()); channels.Add(channel); Debug.Assert(tasks.Count == channels.Count); } /* * await Task.Run(() => * { * Task.WaitAll(tasks.ToArray(), TimeSpan.FromMinutes(1)); * }).ConfigureAwait(false); */ await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(TimeSpan.FromMinutes(1))); // 2020/11/4 观察返回值 List <string> errors = new List <string>(); foreach (var task in tasks) { if (task.IsCompleted == false) { // 中断那些超时后还没有结束的 channel int index = tasks.IndexOf(task); var channel = channels[index]; channel.ZClient.CloseConnection(); continue; // 不计入报错? } var result = await task; if (result.Value == -1) { errors.Add(result.ErrorInfo); } } if (errors.Count == 0) { return(new NormalResult()); } else { return new NormalResult { Value = -1, ErrorInfo = StringUtil.MakePathList(errors, "; ") } }; } finally { _searching = false; } }