SORU
27 Ocak 2014, PAZARTESİ


Hızlı dize topluluğu arama yolu

Sorun:

Ben bir metin civarında dosya var120,000bir koleksiyonu saklamak ve daha sonra Bu koleksiyon üzerinde arama yapmak istiyorum hangi kullanıcılar (dizeleri).

Arama yöntemini kullanıcı TextBox bir metni değiştirmek ve sonuç dizeleri olmalıdır her zaman ortaya çıkariçerirTextBox metin.

Listeyi değiştirmek, sadece sonuçlar çekin ve ListBox koymak zorunda değilim.

Ben şimdiye kadar denedim ne var:

Harici bir metin dosyası (bir zamanlar tabi): string girişleri terkediyorum iki farklı koleksiyon/konteyner ile çalıştım

  1. List<string> allUsers;
  2. HashSet<string> allUsers;

Aşağıdaki ile LINQ sorgu:

allUsers.Where(item => item.Contains(textBox_search.Text)).ToList();

(Kullanıcı arama metni değiştirmek için harekete arama benim olay:

private void textBox_search_TextChanged(object sender, EventArgs e)
{
    if (textBox_search.Text.Length > 2)
    {
        listBox_choices.DataSource = allUsers.Where(item => item.Contains(textBox_search.Text)).ToList();
    }
    else
    {
        listBox_choices.DataSource = null;
    }
}

Sonuçlar:

Hem bana kötü tepki süresi (her tuşa basın arasında 1-3 saniye civarında) verdi.

Soru:

Nerede benim performans sorunu olduğunu düşünüyor musunuz? Kullandım koleksiyonu? Arama yöntemi? Hem?

Nasıl daha akıcı daha iyi performans ve işlevsellik alabilir miyim?

CEVAP
27 Ocak 2014, PAZARTESİ


Eğer giriş değiştirilirse bitince geri çağrı yöntemini çağırmak, ya da sadece süzme yeniden hangi bir arka plan iş parçacığı üzerinde filtreleme görev yaptığını düşünebilirsiniz.

Genel fikir bu şekilde kullanabilmek için:

public partial class YourForm : Form
{
    private readonly BackgroundWordFilter _filter;

    public YourForm()
    {
        InitializeComponent();

        // setup the background worker to return no more than 10 items,
        // and to set ListBox.DataSource when results are ready

        _filter = new BackgroundWordFilter
        (
            items: GetDictionaryItems(),
            maxItemsToMatch: 10,
            callback: results => 
              this.Invoke(new Action(() => listBox_choices.DataSource = results))
        );
    }

    private void textBox_search_TextChanged(object sender, EventArgs e)
    {
        // this will update the background worker's "current entry"
        _filter.SetCurrentEntry(textBox_search.Text);
    }
}

Kaba bir kroki gibi bir şey olacaktır:

public class BackgroundWordFilter : IDisposable
{
    private readonly List<string> _items;
    private readonly AutoResetEvent _signal = new AutoResetEvent(false);
    private readonly Thread _workerThread;
    private readonly int _maxItemsToMatch;
    private readonly Action<List<string>> _callback;

    private volatile bool _shouldRun = true;
    private volatile string _currentEntry = null;

    public BackgroundWordFilter(
        List<string> items,
        int maxItemsToMatch,
        Action<List<string>> callback)
    {
        _items = items;
        _callback = callback;
        _maxItemsToMatch = maxItemsToMatch;

        // start the long-lived backgroud thread
        _workerThread = new Thread(WorkerLoop)
        {
            IsBackground = true,
            Priority = ThreadPriority.BelowNormal
        };

        _workerThread.Start();
    }

    public void SetCurrentEntry(string currentEntry)
    {
        // set the current entry and signal the worker thread
        _currentEntry = currentEntry;
        _signal.Set();
    }

    void WorkerLoop()
    {
        while (_shouldRun)
        {
            // wait here until there is a new entry
            _signal.WaitOne();
            if (!_shouldRun)
                return;

            var entry = _currentEntry;
            var results = new List<string>();

            // if there is nothing to process,
            // return an empty list
            if (string.IsNullOrEmpty(entry))
            {
                _callback(results);
                continue;
            }

            // do the search in a for-loop to 
            // allow early termination when current entry
            // is changed on a different thread
            foreach (var i in _items)
            {
                // if matched, add to the list of results
                if (i.Contains(entry))
                    results.Add(i);

                // check if the current entry was updated in the meantime,
                // or we found enough items
                if (entry != _currentEntry || results.Count >= _maxItemsToMatch)
                    break;
            }

            if (entry == _currentEntry)
                _callback(results);
        }
    }

    public void Dispose()
    {
        // we are using AutoResetEvent and a background thread
        // and therefore must dispose it explicitly
        Dispose(true);
    }

    private void Dispose(bool disposing)
    {
        if (!disposing)
            return;

        // shutdown the thread
        if (_workerThread.IsAlive)
        {
            _shouldRun = false;
            _currentEntry = null;
            _signal.Set();
            _workerThread.Join();
        }

        // if targetting .NET 3.5 or older, we have to
        // use the explicit IDisposable implementation
        (_signal as IDisposable).Dispose();
    }
}

Ayrıca, aslında veli Form bertaraf _filter örnek atılması gerekir. Ve açık düzenlemeniz gerekir bu demektir Form'Dispose yöntem (YourForm.Designer.cs dosya içinde) bir şey gibi görünmesi için:

// inside "xxxxxx.Designer.cs"
protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        if (_filter != null)
            _filter.Dispose();

        // this part is added by Visual Studio designer
        if (components != null)
            components.Dispose();
    }

    base.Dispose(disposing);
}

Benim makinede test ve daha karmaşık bir çözüm için gitmeden önce bu profil, bu yüzden oldukça hızlı bir şekilde çalışır.

Bunu söyledikten sonra, "daha karmaşık bir çözüm olarak" belki olur saklanması son bir kaç sonuçlarında bir sözlük, ve sonra sadece filtre onları eğer ortaya çıkarsa yeni girdi farklıdır sadece ilk ve son karakter.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • aki6336

    aki6336

    14 AĞUSTOS 2008
  • kylediablo

    kylediablo

    8 Ocak 2007
  • Mindy

    Mindy

    20 NİSAN 2006