วิธีใดเป็นวิธีที่ดีที่สุดในการค้นหา IReliableDictionary

อ้างอิงจากโพสต์เหล่านี้:

แปลง IReliableDictionary เป็น IList

คืออะไร วิธีการที่เหมาะสมที่สุดในการสืบค้นคอลเลกชันพจนานุกรมที่เชื่อถือได้

ฉันควรจะใช้ Linq เพื่อสืบค้น IReliableDictionary ได้ แต่ปรากฏว่าอินเทอร์เฟซนี้ไม่ใช้งาน IEnumerable อีกต่อไป และส่วนขยาย Linq ไม่พร้อมใช้งาน อย่างน้อยในเวอร์ชัน 5.0.0.0 ของแอสเซมบลี Microsoft.ServiceFabric.Data.Interfaces

หากสิ่งนี้เป็นจริง วิธีใดคือวิธีที่ดีที่สุดในการค้นหา IReliableDictionary


person RWilkinson    schedule 26.04.2016    source แหล่งที่มา


คำตอบ (4)


ใช่ เราได้ลบ IEnumerable ออกจากคอลเลกชั่นที่เชื่อถือได้ในรุ่น GA แล้ว ดังที่ Allan T กล่าวไว้ คอลเลกชั่นที่เชื่อถือได้นั้นไม่เหมือนกับคอลเลกชั่น .NET ทั่วไป แม้ว่าคอลเลกชั่นเหล่านั้นจะมีโครงสร้างข้อมูลพื้นฐานที่เหมือนกันก็ตาม ความแตกต่างที่สำคัญประการหนึ่งที่คุณอาจสังเกตเห็นก็คือการดำเนินการทั้งหมดเป็นแบบอะซิงโครนัส เนื่องจากการล็อกซีแมนทิกส์และ I/O สำหรับการจำลองแบบและการอ่านดิสก์ เป็นส่วนหลังที่ผลักดันให้เกิดการตัดสินใจลบ IEnumerable เนื่องจากเป็นแบบซิงโครนัสอย่างเคร่งครัดและเรากลับไม่ทำเช่นนั้น ตอนนี้เราใช้ IAsyncEnumerable แทน ซึ่ง ณ ตอนนี้ยังไม่รองรับวิธีการขยาย LINQ ครบชุด

เรากำลังดำเนินการเกี่ยวกับวิธีการขยาย LINQ แบบอะซิงโครนัส แต่ในระหว่างนี้ มีสองวิธีในการทำงานกับ IAsyncEnumerable

Eli Arbel มีวิธีการขยายแบบอะซิงก์บน Gist ที่เป็นสะพานเชื่อมไปยัง System.Interactive.Async และการใช้งาน async ของ Select, SelectMany และ Where

หรือคุณสามารถ wrap IAsyncEnumerable ใน IEnumerable ปกติ ที่เพียงแค่ล้อมการโทรแบบอะซิงโครนัสด้วยวิธีซิงโครนัส และนั่นจะทำให้คุณได้รับชุดเมธอดส่วนขยาย LINQ ครบชุดอีกครั้ง จากนั้นคุณสามารถใช้วิธีการขยายในการสืบค้น LINQ ทั่วไป:

        using (ITransaction tx = this.StateManager.CreateTransaction())
        {
            var x = from item in (await clusterDictionary.CreateEnumerableAsync(tx)).ToEnumerable()
                   where item.Value.Status == ClusterStatus.Ready
                   orderby item.Value.CreatedOn descending
                   select new ClusterView(
                       item.Key,
                       item.Value.AppCount,
                       item.Value.ServiceCount,
                       item.Value.Users.Count(),
                       this.config.MaximumUsersPerCluster,
                       this.config.MaximumClusterUptime - (DateTimeOffset.UtcNow - item.Value.CreatedOn.ToUniversalTime()));

        }
person Vaclav Turecek    schedule 27.04.2016
comment
หมายเหตุเล็กๆ น้อยๆ - ส่วนขยายจัดเตรียมสะพานเชื่อมไปยังไลบรารี Ix-Async NuGet ซึ่งรวมถึงการใช้งาน async LINQ เต็มรูปแบบ ส่วนพื้นฐานอ้างถึงเวอร์ชันอะซิงก์ของตัวดำเนินการ ซึ่งฉันได้ใช้งานเฉพาะ SelectAsync, SelectManyAsync และ WhereAsync - person Eli Arbel; 28.04.2016
comment
(ตัวดำเนินการอะซิงก์เหล่านี้รองรับสถานการณ์ เช่น การสืบค้นข้ามคอลเลกชันอื่นๆ) - person Eli Arbel; 28.04.2016
comment
ขอบคุณสำหรับการชี้แจง Eli ฉันอัปเดตคำตอบแล้ว - person Vaclav Turecek; 28.04.2016
comment
ขอบคุณสำหรับการขยาย! มันมีประโยชน์มาก/มีประโยชน์ ฉันสามารถแทนที่โค้ดเก่าของฉันได้โดยใช้ส่วนขยายเหล่านี้ มันใช้งานได้ทันที - person alltej; 29.04.2016
comment
ขอขอบคุณที่อธิบายเหตุผลในการลบการสนับสนุน LINQ ฉันคิดว่าเป็นเช่นนั้น ไลบรารีส่วนขยายและ nuget ดูมีแนวโน้มดี และฉันจะลองดู คงจะดีไม่น้อยหากมีการใช้งาน async LINQ ในไลบรารีหลัก เนื่องจากนี่จะเป็นคุณลักษณะที่น่าสนใจ มีไทม์ไลน์สำหรับสิ่งเหล่านี้หรือไม่? - person RWilkinson; 29.04.2016

ฉันไม่รู้ว่ามันเป็นวิธีที่ "ดีที่สุด" หรือไม่ แต่ฉันได้ใช้สิ่งต่อไปนี้

public static async Task<IList<KeyValuePair<Guid, T>>> QueryReliableDictionary<T>(IReliableStateManager stateManager, string collectionName, Func<T, bool> filter)
{
    var result = new List<KeyValuePair<Guid, T>>();

    IReliableDictionary<Guid, T> reliableDictionary =
        await stateManager.GetOrAddAsync<IReliableDictionary<Guid, T>>(collectionName);

    using (ITransaction tx = stateManager.CreateTransaction())
    {
        IAsyncEnumerable<KeyValuePair<Guid, T>> asyncEnumerable = await reliableDictionary.CreateEnumerableAsync(tx);
        using (IAsyncEnumerator<KeyValuePair<Guid, T>> asyncEnumerator = asyncEnumerable.GetAsyncEnumerator())
        {
            while (await asyncEnumerator.MoveNextAsync(CancellationToken.None))
            {
                if (filter(asyncEnumerator.Current.Value))
                    result.Add(asyncEnumerator.Current);
            }
        }
    }
    return result;
}

คุณใช้วิธีการนี้โดยส่งผ่าน StateManager ชื่อของคอลเลกชันที่คุณต้องการสืบค้น และฟังก์ชัน lambda พร้อมตรรกะการสืบค้นของคุณ ตัวอย่างเช่น:

var queryResult = await QueryReliableDictionary<string>(this.StateManager, "CustomerCollection", name => !string.IsNullOrWhiteSpace(name) && (name.IndexOf("fred", StringComparison.OrdinalIgnoreCase) >= 0));
person Nick Barrett    schedule 28.04.2016
comment
ฉันควรจะพูดถึงว่าฉันใช้ Guid's สำหรับคีย์พจนานุกรมของฉัน หากคุณต้องการใช้ประเภทอื่น คุณจะต้องปรับโค้ดให้เหมาะสม - person Nick Barrett; 28.04.2016
comment
นี่เกือบจะเหมือนกับสิ่งที่ฉันทำในที่สุดขอบคุณ - person RWilkinson; 29.04.2016

ในขณะที่เขียนคำตอบนี้ IAsyncEnumerable เป็นส่วนหนึ่งของไลบรารี dotnet และ C# 8.0 เพิ่มน้ำตาลไวยากรณ์เพื่อรองรับ

ปัญหาคือ ServiceFabric ใช้คำจำกัดความของตัวเองเป็น IAsyncEnumerable ดังนั้นคุณจึงไม่สามารถใช้วิธีการขยาย dotnet และตัวช่วย C# กับมันได้

วิธีแก้ปัญหาที่ฉันคิดขึ้นมาคือการแปลง IAsyncEnumerable ของ ServiceFabric เป็นเนทิฟโดยใช้ wrapper แบบธรรมดา:

using System.Threading;
using System.Threading.Tasks;

using Generic = System.Collections.Generic;
using Fabric = Microsoft.ServiceFabric.Data;

public static class FabricAsyncEnumerableExtensions
{
    /// <summary>
    /// Converts ServiceFabric <see cref="Microsoft.ServiceFabric.Data.IAsyncEnumerable"/> to dotnet native <see cref="System.Collections.Generic.IAsyncEnumerable"/>.
    /// </summary>
    public static Generic.IAsyncEnumerable<T> ToGeneric<T>(this Fabric.IAsyncEnumerable<T> source) =>
        new AsyncEnumerableWrapper<T>(source);

    private class AsyncEnumerableWrapper<T> : Generic.IAsyncEnumerable<T>
    {
        private readonly Fabric.IAsyncEnumerable<T> _source;

        public AsyncEnumerableWrapper(Fabric.IAsyncEnumerable<T> source) => _source = source;

        public Generic.IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken _ = default)
        {
            Fabric.IAsyncEnumerator<T> enumerator = _source.GetAsyncEnumerator();
            return new AsyncEnumeratorWrapper<T>(enumerator);
        }
    }

    private class AsyncEnumeratorWrapper<T> : Generic.IAsyncEnumerator<T>
    {
        private readonly Fabric.IAsyncEnumerator<T> _source;

        public AsyncEnumeratorWrapper(Fabric.IAsyncEnumerator<T> source) => _source = source;

        public async ValueTask DisposeAsync() =>
            await Task.Run(_source.Dispose).ConfigureAwait(false);

        public async ValueTask<bool> MoveNextAsync() =>
            await _source.MoveNextAsync(default).ConfigureAwait(false);

        public T Current => _source.Current;
    }
}

การใช้มันกลายเป็นเรื่องง่ายเหมือนกับการเรียกเมธอดส่วนขยาย จากนั้นใช้มันตามปกติ IAsyncEnumerable:

Fabric.IAsyncEnumerable<KeyValuePair<Guid, Product>> asyncProducts = GetAsyncProducts();
return await asyncProducts.ToGeneric()
    .Select(p => p.Value)
    .ToListAsync()
    .ConfigureAwait(false);
person Vitaliy Ulantikov    schedule 17.05.2020

เท่าที่ฉันรู้ พจนานุกรมที่เชื่อถือได้ของ Service Fabric อาจดูเหมือนพจนานุกรม .NET ทั่วไป แต่ก็ไม่เหมือนกันจริงๆ ดังนั้นวิธีการบางอย่างอาจไม่รองรับพจนานุกรมหรือคิวที่เชื่อถือได้ของ SF

person alltej    schedule 27.04.2016
comment
เมื่อเร็ว ๆ นี้ในเดือนตุลาคม 2558 ผู้จัดการโปรแกรมอาวุโสจาก MS โพสต์ว่า LINQ พร้อมใช้งานในคอลเลกชันนี้ (ลิงก์ที่สองด้านบน) ดูเหมือนว่าความสามารถในการใช้ส่วนขยาย LINQ จะถูกลบออกก่อน GA of Service Fabric - person RWilkinson; 27.04.2016