У меня тут небольшая проблема, и мне нужна помощь.
Мой код - это бесконечный поиск на веб-страницах шаблонов, которые, когда он находит что-то новое, записывает это в файл.
Однако иногда информация, которую я собираю, уже находится в файле, но не обновляется, и мне не нужны повторяющиеся записи в моем файле.
Поэтому я просто создал список строк, добавив туда каждую запись, и каждый раз, когда код находит то, что ищет, он проверяет, есть ли уже строка в этом списке перед записью в файл.
Вы можете ясно видеть, почему это плохая идея ... Поскольку он работает круглосуточно, 7 дней в неделю, этот список будет бесконечно увеличиваться. Но есть загвоздка. Я на 100% уверен, что информация, которую я ищу, никогда не повторится, если прошло 15 минут.
Итак, что я действительно хочу, так это исключить элементы, которые находятся в этом списке, в течение 15 минут. Я просто не могу придумать что-нибудь простое и / или элегантное, чтобы сделать это. Или я не знаю, есть ли какая-то структура данных или библиотека, которые могут решить эту проблему за меня.
Вот почему я спрашиваю здесь: как лучше всего создать своего рода «временный список», где элементы, которые есть какое-то время, удаляются в конце итерации?
Заранее спасибо.
Вы пробовали встроенный в .NET ПамятьКэш?
Вы можете установить политику кеширования, которая включает абсолютный тайм-аут, что, я думаю, вам и нужно.
Вам понадобится что-то работающее, что периодически сокращает список.
В прошлом я делал следующее:
ConcurrentBag<Tuple<DateTime, T>>
вместо List<T>
theBag.Add(Tuple.Create(DateTime.Now, myObject));
Это более активный подход, но он довольно простой. Однако, поскольку теперь вы работаете с двумя потоками, вы должны быть осторожны, чтобы не зайти в тупик. Поэтому я использовал что-то вроде ConcurrentBag
. Вы также можете посмотреть другие коллекции Concurrent
. Вы упомянули очередь, поэтому можете попробовать ConcurrentQueue
Внимательно изучите библиотеку кеширования, как предлагали другие, и взвесьте свои варианты. Полная библиотека кеширования может оказаться излишней.
Хорошо поймал. Я не знал о локальной копии потока. В этом случае он по-прежнему будет работать, но производительность снизится. Тем не менее, я считаю, что основной принцип хранения Tuple<DateTime, T>
- хороший. Вы даже можете использовать простую старую очередь и проверять дату при выходе из очереди. Если он истек, просто продолжайте.
Спасибо, нашел ссылку здесь. Не возражайте против вашего простого дизайна.
Вместо списка строк создайте класс, имеющий свойство строки и свойство отметки времени. При создании экземпляра класса автоматически заполняйте свойство отметки времени значением DateTime.Now.
Каждый раз, когда вы просматриваете список, чтобы увидеть, существует ли строка, также проверяйте свойство timestamp и отбрасывайте любой элемент старше 15 минут.
пример
class TimeStampedSearchResult
{
public string SearchResult { get; set; }
public DateTime TimeStamp { get; private set; }
public TimeStampedSearchResult(string searchResult)
{
SearchResult = searchResult;
TimeStamp = DateTime.Now;
}
public void UpdateTimeStamp()
{
TimeStamp = DateTime.Now;
}
}
тогда вы можете использовать это как:
public SearchForever()
{
//the results list
List<TimeStampedSearchResult> results = new List<TimeStampedSearchResult>();
//a list of expired results to remove from results list
List<TimeStampedSearchResult> expiredResults = new List<TimeStampedSearchResult>();
while (true)
{
//search for a result
var searchResult = new TimeStampedSearchResult(SearchForStuff());
bool found = false;
//iterate our list
foreach (var result in results)
{
if (result.SearchResult == searchResult.SearchResult)
{
result.UpdateTimeStamp();
found = true;
}
else
{
if (result.TimeStamp < DateTime.Now.AddMinutes(-15))
{
expiredResults.Add(result);
}
}
}
if (!found)
{
//add to our results list
results.Add(searchResult);
//write result to file
WriteResult(searchResult.SearchResult, "myfile.txt")
}
//remove expired results
foreach (var oldResult in expiredResults)
results.Remove(oldResult);
//make sure you clear the expired results list too.
expiredResults.Clear();
}
}
Буквально изобретая колесо MemoryCache
.
ConcurrentBag
использует локальное хранилище потоков и имеет низкую производительность в вашем сценарии. Его лучше всего использовать, когда каждый поток одновременно производит и потребляет, чтобы избежать снижения производительности при краже элементов.