LINUX.ORG.RU

Как правильно жонглировать двумя динамическими массивами для создания быстрого буфера?

 , , , ,


0

1

Есть класс, ещё не дописанный. Он реализует очередь принятых UDP пакетов. И резиновый буфер, возможно его следовало бы реализовать на классе набора, а не на двух массивах. Но я решил что так он будет работать быстрее в случае накопления большой очереди. Хотя в моём проекте большой очереди не будет и я страдаю от перфекционизма.

Алгоритм. Новые пакеты дописываются в конец текущего массива, при определённых условиях заполненности, содержимое текущего массива копируется будущий начиная с текущего указателя.

TextBuffers[f].Insert(TextBuffers[p].Copy(CurrentPosition))
и старый буфер очищается, после чего текущим становится новый. Подробнее в тексте функции SwapBuffers()

Но вот как понять оптимальный момент в который надо начинать этот процесс, я не знаю. Если ждать слишком мало, то то тасоваться в памяти данные будут слишком часто. Если ждать слишком долго, то пустые элементы будут занимать память зря. А если ещё и очередь успеет накопиться, то перемещать её будет сравнительно долговато. Хотя в моём проекте большой очереди в принципе не будет. Но меня заинтересовал сам вопрос. Как вычислить оптимальный момент для переноса буфера в чистый массив?


' Класс для отслеживания событий UDP сокета и приёма текстовых данных из него

Public SocketUDP As New UdpSocket

Private Const CountBuffers As Integer = 2
Private Const MaxBuffers As Integer = 1 ' CountBuffers -1
Private Const WaitTime As Float = 0.02 ' Время блокирующего ожидания прихода пакета

Private TextBuffers As String[][CountBuffers]
Private CurrentBufferNumber As Integer ' Текущий буфер
Private CurrentPosition As Integer ' Текущая позиция для чтения в текущем буфере
Private CountPackets As Integer ' Количество принятых пакетов

Public ErrorToMessage As Boolean ' Если равно True, то ошибка будет в виде сообщения попадать в буфер
Public ErrorToMessageText As String ' Текст сообщения о ошибке, например "error=" и после сразу код ошибки
Public ErrorLastCode As Integer ' Код последней ошибки

Public Sub _new()
  Dim a As Integer
  For a = 0 To MaxBuffers
    TextBuffers[a] = New String[]
  Next
End
Public Function GetTextMessage(Optional TextNoMessege As String = "") As String ' Возвращает пакет из буфера
  Dim r As String
  If CountPackets > 0 Then
    ' Пакет есть в буфере
    r = TextBuffers[CurrentBufferNumber][CurrentPosition]
    TextBuffers[CurrentBufferNumber][CurrentPosition] = ""
    If CurrentPosition < TextBuffers[CurrentBufferNumber].Max Then CurrentPosition = CurrentPosition + 1 ' Передвинуть текущую позицию при условии что она не крайняя
    CountPackets = CountPackets - 1
  Else
    ' Пакета нет в буфере
    If TextNoMessege <> "" Then
      r = TextNoMessege
    Else
      Do While CountPackets = 0
        Wait WaitTime
      Loop
    Endif
  Endif
  
  ' Нужно ли сейчас передвинуть буфер?
  
  
  
  Return r
End


Public Function CountMessages() As Integer
  Return CountPackets
End

Public Sub SwapBuffers() ' Функция меняет буферы, тем самым осовобождая память.
  Dim a As Integer, m As Integer
  Dim p As Integer, f As Integer ' Прошлый и будущий буферы
  p = CurrentBufferNumber
  f = f + 1
  If f > MaxBuffers Then f = 0 ' Вычисление номера следующего буфера
  m = TextBuffers[p].Max
  
  If TextBuffers[p].Count = 0 Then TextBuffers[p].Add("") ' Если буфер совсем пустой, то добавить балластный элемент дабы в цикле не произошла ошибка
  ' Можно было бы поставить в условие сам цикл, но опасаюсь что это приведёт к потенциальной запутанности при усложнении
  TextBuffers[f].Insert(TextBuffers[p].Copy(CurrentPosition))
  'For a = CurrentPosition To m
  '  TextBuffers[f].Add(TextBuffers[p][a])
  'Next
  CurrentBufferNumber = f
  TextBuffers[p].Clear ' Очистка буфера
  CurrentPosition = 0
End


Public Sub SocketUDP_Read()
  Dim s As String
  Dim sCad As String
  Read #SocketUDP, s, Lof(SocketUDP) ' Считать пакет из сокета
  If Len(s) > 0 Then
    TextBuffers[CurrentBufferNumber].Add(s) ' Добавить пакет в буфер
    CountPackets = CountPackets + 1
  End If
End
Public Sub SocketUDP_Error()
  ErrorLastCode = SocketUDP.Status
  If ErrorToMessage Then
    TextBuffers[CurrentBufferNumber].Add(ErrorToMessageText & s) ' Добавить пакет с описанием ошибки в буфер
    CountPackets = CountPackets + 1
  Endif
End
☆☆☆

Последнее исправление: rezedent12 (всего исправлений: 1)

Ответ на: комментарий от Stahl

А что это за язык? Какой-то диалект Паскаля? Почему-то именно Паскаль напомнил...

Gambas, похож в большей степени на Visual Basic и в меньшей степени на Java.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от rezedent12

Наверное, стоит добавлять название языка в теги, на худой конец - в первый абзац ОП, чтобы таких вопросов не было.

По коду да, первым делом VBA напомнило...

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от Stahl

Забавно. Только вот рак на логотипе :)

Креветка.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от hobbit

Наверное, стоит добавлять название языка в теги, на худой конец - в первый абзац ОП, чтобы таких вопросов не было.

Добавил.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от rezedent12

Алгоритм. Новые пакеты дописываются в конец текущего массива, при определённых условиях заполненности, содержимое текущего массива копируется будущий начиная с текущего указателя.
и старый буфер очищается, после чего текущим становится новый.

Ну и где логика? Надо, после того как обработал буфер, его очистить. А не копировать один массив в другой.

outsider ★★
()
Последнее исправление: outsider (всего исправлений: 1)

Я когда код увидел, у меня первая мысль была, что Бабукшин вернулся со своим антивирусом на вижузал васике.

Потом вспомнил, что резидент пишет на gambas.

Deleted
()

Класс для отслеживания событий UDP сокета и приёма текстовых данных из него

Эээ... То есть ты велосипедишь TCP поверх UDP?

А ты в курсе, что UDP пакеты могут не дойти, дойти в иной последовательности или дойти дублями?

Иными словами, вместо «Hello, World» ты можешь запросто получить «Hell,roW,d».

Deleted
()
Ответ на: комментарий от outsider

Ну и где логика? Надо, после того как обработал буфер, его очистить. А не копировать один массив в другой.

Ну так представь ситуацию, в буфере ещё 12 элементов, а очищенных уже 5000.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от Deleted

Эээ... То есть ты велосипедишь TCP поверх UDP?

Нет. У меня нет потребности поддерживать соединение.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от Deleted

ты можешь запросто получить «Hell,roW,d

А ютуб не на UDP работает?

anonymous
()
Ответ на: комментарий от Deleted

А очередь, мне нужна что я не знаю как работает сам буфер сокета.

rezedent12 ☆☆☆
() автор топика
Ответ на: комментарий от rezedent12

ну так и обработай последние 12 и очисти все, а то смысл сохранить 12 элементов в другой массив и потом их все равно обрабатывать.

outsider ★★
()
Ответ на: комментарий от outsider

ну так и обработай последние 12 и очисти все, а то смысл сохранить 12 элементов в другой массив и потом их все равно обрабатывать.

В принципе да. Но меня интересовала сама задача хранения.

rezedent12 ☆☆☆
() автор топика

Зачем так сложно, зачем вообще чтото копировать? Делаешь кольцевой буффер на массиве, когда он кончается выделяешь новый массив в полтора раза больше, пишешь в него а читаешь из старого пока тот не кончится. Дершишь стек этих массивов. Получаешь резиновый буффер с нулевым оверхедом.

anonymous
()
Ответ на: комментарий от anonymous

Зачем так сложно, зачем вообще чтото копировать? Делаешь кольцевой буффер на массиве, когда он кончается выделяешь новый массив в полтора раза больше, пишешь в него а читаешь из старого пока тот не кончится. Дершишь стек этих массивов. Получаешь резиновый буффер с нулевым оверхедом.

Здравая идея, но мне уже посоветовали готовый класс.

rezedent12 ☆☆☆
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.