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
List<string> allUsers;
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
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.
Hızlı dize PHP bir tamsayı dönüştürmek...
Eğer bir dize PHP JSON olup olmadığını...
Hızlı dize arama algoritması nedir?...
Hızlı Dize karakterleri değiştirmek iç...
Bir dize kontrol etmek için en hızlı y...