Пример #1
0
        /// <summary>
        /// 同时探索多个节点。适用于文章节点。注意,此函数仅在查询方面进行了优化,
        /// 如果其他线程正在探索此节点,则等待此节点探索完毕。
        /// </summary>
        private async Task FetchPapersAsync(IReadOnlyCollection <KgNode> paperNodes)
        {
            Debug.Assert(paperNodes != null);
            // 注意,有些节点可能仍处于 正在探索 的状态。
            //      需要在返回前等待这些正在探索的节点。
            var nodesToFetch = paperNodes.Where(n => GetStatus(n.Id).TryMarkAsFetching(NodeStatus.PaperFetching))
                               .ToArray();

            if (nodesToFetch.Length == 0)
            {
                goto WAIT_FOR_EXPLORATIONS;
            }
            await Task.WhenAll(nodesToFetch.Select(n => n.Id)
                               .Partition(SEB.MaxChainedIdCount)
                               .Select(ids =>
            {
                // 假定 Partition 返回的是 IList / ICollection
                var idc = (ICollection <long>)ids;
                return(SearchClient.EvaluateAsync(SEB.EntityIdIn(idc),
                                                  SEB.MaxChainedIdCount, ConcurrentPagingMode.Pessimistic,
                                                  page =>
                {
                    if (page.Entities.Count < idc.Count)
                    {
                        Logger.Magik.Warn(this, "批量查询实体 Id 时,返回结果数量不足。期望:{0},实际:{1}。", idc.Count,
                                          page.Entities.Count);
                    }
                    foreach (var entity in page.Entities)
                    {
                        ExplorePaperUnsafe(entity);
                    }
                    return Task.CompletedTask;
                }));
            }));

            foreach (var n in nodesToFetch)
            {
                GetStatus(n.Id).MarkAsFetched(NodeStatus.PaperFetching);
            }
WAIT_FOR_EXPLORATIONS:
            //确保返回前,所有 Fetching 的节点已经由此线程或其他线程处理完毕。
            var waitResult = await Task.WhenAll(paperNodes.Select(n =>
                                                                  GetStatus(n.Id).UntilFetchedAsync(NodeStatus.PaperFetching)));

            Debug.Assert(waitResult.All(r => r));
        }
Пример #2
0
        /// <summary>
        /// 同时探索多个节点。适用于文章节点。注意,此函数仅在查询方面进行了优化,
        /// 如果其他线程正在探索此节点,则等待此节点探索完毕。
        /// </summary>
        private async Task FetchPapersAsync(IReadOnlyCollection <KgNode> paperNodes, string constraint)
        {
            Debug.Assert(paperNodes != null);
            if (constraint == null)
            {
                await FetchPapersAsync(paperNodes);

                return;
            }
            // 1. 注意,有些节点可能仍处于 正在探索 的状态。
            //      需要在返回前等待这些正在探索的节点。
            // 2. 很不幸,一旦标记一个节点开始探索后,没有办法再标记为未探索,
            //      所以在有约束的情况下,只能在内层循环中对节点分别标记。
            var nodesToFetch = paperNodes.Where(n => GetStatus(n.Id).GetFetchingStatus(NodeStatus.PaperFetching) == FetchingStatus.Unfetched)
                               .ToArray();

            if (nodesToFetch.Length == 0)
            {
                goto WAIT_FOR_EXPLORATIONS;
            }
            await Task.WhenAll(nodesToFetch.Select(n => n.Id)
                               .Partition(SEB.MaxChainedIdCount)
                               .Select(ids =>
            {
                // 假定 Partition 返回的是 IList / ICollection
                var idc = (ICollection <long>)ids;
                return(SearchClient.EvaluateAsync(SEB.And(SEB.EntityIdIn(idc), constraint),
                                                  SEB.MaxChainedIdCount,
                                                  ConcurrentPagingMode.Optimistic,
                                                  async page =>
                {
                    foreach (var entity in page.Entities)
                    {
                        await ExplorePaperAsync(entity);
                    }
                }));
            }));

WAIT_FOR_EXPLORATIONS:
            ;
        }