FreeBasic
Главная
Вход
Регистрация
Пятница, 29.03.2024, 15:27Приветствую Вас Гость | RSS
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 2 из 4
  • «
  • 1
  • 2
  • 3
  • 4
  • »
Форум » Freebasic » Вопросы по языку FreeBasic » Тестирование разных контейнеров и другая болтовня (тестирование хеш таблиц , map и пр.)
Тестирование разных контейнеров и другая болтовня
zamabuvaraeuДата: Понедельник, 17.01.2022, 11:02 | Сообщение # 16
Подполковник
Группа: Друзья
Сообщений: 147
Репутация: 4
Статус: Offline
Может быть список у них в виде массива реализован?
Для виндоуз: может быть вместо функции Allocate попробовать частную кучу HeapCreate+HeapAlloc с флагом HEAP_NO_SERIALIZE.
 
haavДата: Понедельник, 17.01.2022, 11:13 | Сообщение # 17
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Вчера , когда уже отключил компьютер и ложился спать , мне пришло осознание. Нет никаких чудес со связанным списком, просто:
1) я компилировал с опцией -exx (то есть закладывал в код по сути отладку). Если компилировать без этого , то скорость пуриковского связанного списка быстрее лишь в 1.5 раза. Это уже не в 4 раза!!!
2) я уже понял , что классическая схема создания списка здесь неуместна. Надо мыслить шире и начинать хитрить. И решение в голову пришло сразу же.
Чтобы было понятнее, выглядеть список будет так:
Код

pNode1      ->        pNode2            ->           ....
   |                    |
array(31)             array(31)


То есть в каждом элементе списка массив для данных. При создании например pNode1 сразу же выделяется память для массива. И следующие 30 добавлений память не выделяется , а просто данные заносятся в массив. Когда место в массиве заканчивается , создается новый элемент списка pNode2 опять же с массивом. Это значительно увеличит скорость по сравнению с классической схемой создания.
Да эта реализация сложнее , но не настолько , чтобы ее невозможно было написать при желании. И в принципе вот набросок кода для добавления и получения данных:

Код
type tData as Long

type T_NODE as TNODE ptr

type TNODE_M
    
    p(31) as tData
    
    bCurIndex as byte
    
    pRootNode as T_NODE ptr
    
End Type

type TNODE
    
    pNext as TNODE ptr
    
    pPrev as TNODE ptr
    
    pArr as TNODE_M
    
    bFill as ULong
    
    bNextIndex as Byte
    
End Type

type TLIST
    
    pFirst as TNODE ptr = 0
    
    pLast as TNODE ptr = 0
    
    declare sub add(pData as tData)
    
    declare sub insert(p as any ptr , pData as tData)
    
    declare function getFirst() as any ptr
    
    declare function getLast() as any ptr
    
    declare function getPrev(p as any ptr) as any ptr
    
    declare function getNext(p as any ptr) as any ptr
    
    declare function getValue(p as any ptr) as tData
    
    declare sub setValue(p as any ptr , pData as tData)
    
End Type

sub TLIST.add(p as tData)
    
    dim pTemp as TNODE ptr
    
    if pFirst = 0 orelse pLast->bFill = &hFFFFFFFF then
  
  pTemp = callocate(sizeof(TNODE))
  
  if pFirst then
   
   pLast->pNext = pTemp
   
  else
  
   pFirst = pTemp
   
  EndIf
  
  pLast = pTemp
  
    else
  
  pTemp = pLast
  
    EndIf
    
    pTemp->bFill = Bitset(pTemp->bFill, pTemp->bNextIndex)
    
    pTemp->pArr.p(pTemp->bNextIndex) = p
    
    pTemp->pArr.bCurIndex = pTemp->bNextIndex
    
    pTemp->pArr.pRootNode = cast(T_NODE ptr,pTemp)
    
    pTemp->bNextIndex+=1
    
End Sub

var t = timer

dim p as TLIST

for i as long = 0 to 10000000
    
    p.add(i)
    
Next

dim p0 as TNODE ptr = p.pFirst

while p0
    
    for i as Long = 0 to 31
  
  if bit(p0->bFill , i) then
   
   var w =p0->pArr.p(i)
   
  EndIf
  
    Next
    
    p0 = p0->pNext
    
Wend

? Timer -t


Этот код уже уделывает пуриковский список примерно в 1.35 раза. Сейчас 17 против 23. Да , надо учесть , что еще будут простейшие функции-обертки , но не думаю , что это сильно изменит результат.


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
DarkDemonДата: Понедельник, 17.01.2022, 17:45 | Сообщение # 18
Полковник
Группа: Друзья
Сообщений: 188
Репутация: -2
Статус: Offline
Цитата haav ()
Этот код уже уделывает пуриковский список примерно в 1.35 раза.

Стас, качественный кастом всегда быстрее. Про это уже говорил кстати, что если всё кастом и если он написан не на отвали
то в среднем софтина, долбя по целевой задаче, будет работать быстрее.
 
haavДата: Понедельник, 17.01.2022, 22:13 | Сообщение # 19
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата zamabuvaraeu ()
Может быть список у них в виде массива реализован?


Не , не думаю. Это было бы крайне неэффективно в плане скорости , когда происходит вставка и удаление.

Цитата zamabuvaraeu ()
Для виндоуз: может быть вместо функции Allocate попробовать частную кучу HeapCreate+HeapAlloc с флагом HEAP_NO_SERIALIZE.


Я же тестирую на линуксе.

Цитата DarkDemon ()
Стас, качественный кастом всегда быстрее. Про это уже говорил кстати, что если всё кастом и если он написан не на отвали
то в среднем софтина, долбя по целевой задаче, будет работать быстрее.


Леха , я это хорошо понимаю. Сколько раз нужно было внедрять в свои программы какие-то уже написанные универсальные куски кода, которые казалось бы работают хорошо. Сначала вроде берешь их , но потом понимаешь, что там надо что-то убрать , что-то добавить , что-то изменить и в итоге от начального куска остается призрак.

--------------

Что касается списков , то в принципе я добился того результата , который уже не хуже пуриковского. С обвесками скорость упала немного , но он сопоставима.

Код
Мой лист:
с обертками 0.258  (расход памяти 0.6% от 16GB)
без оберток 0.184  (расход памяти 0.6% от 16GB)

purebasic list:    
0.271  (расход памяти 1.9% от 16GB)


Дописывать вряд ли буду , не в этом была цель. Просто сделал себе вызов достигнуть скорости работы пуриковского списка. Непонятно только, почему пуриковский список жрет памяти в три раза больше чем мой. Вроде размер данных , отсылаемый в список , один и тот же (8 байт).

Код выкладываю напоследок. Сразу скажу , что почти не тестировал на ошибки. Некоторые функции вообще даже не пробовал , просто написал по наитию. Но ниже для интересующихся поясню , как можно реализовать удаление и вставку данных. Может можно что-то и лучше придумать , но мне уже лень. И так вот код:

Код
type tData as Integer

type T_NODE as TNODE ptr

type TNODE_M
    
    p as tData
    
End Type

type TNODE_CUR extends TNODE_M
    
    pRoot as T_NODE ptr
    
End Type

type TNODE
    
    pNext as TNODE ptr
    
    pPrev as TNODE ptr
    
    pArr(31) as TNODE_M
    
    bFill as ULong
    
    bNextIndex as Byte
    
End Type

type TLIST
    
    pFirst as TNODE ptr
    
    pLast as TNODE ptr
    
    pCurent as TNODE_CUR
    
    iCurentIndex as Long
    
    declare sub add(pData as tData)
    
    declare sub insert(pData as tData)
    
    declare function getFirst() as any ptr
    
    declare function getLast() as any ptr
    
    declare function getPrev() as any ptr
    
    declare function getNext() as any ptr
    
    declare function getValue() as tData
    
    declare sub setValue(pData as tData)
    
    declare sub resetList()
    
End Type

sub TLIST.add(p as tData)
    
    dim pTemp as TNODE ptr = any
    
    if pFirst = 0 orelse pLast->bFill = &hFFFFFFFF then
  
  pTemp = callocate(sizeof(TNODE))
  
  if pFirst then
   
   pLast->pNext = pTemp
   
  else
   
   pFirst = pTemp
   
  EndIf
  
  pLast = pTemp
  
    else
  
  pTemp = pLast
  
    EndIf
    
    iCurentIndex = pTemp->bNextIndex
    
    pTemp->bFill = Bitset(pTemp->bFill, iCurentIndex)
    
    pTemp->pArr(iCurentIndex).p = p
    
    pCurent.pRoot = cast(T_NODE ptr, pTemp)
    
    pCurent.p = p
    
    pTemp->bNextIndex+=1
    
End Sub

sub TLIST.insert(pData as tData)
    
    
    
End Sub

function TLIST.getFirst() as any ptr
    
    if pFirst then
  
  for i as Long = 0 to 31
   
   if bit(pFirst->bFill , i) then
    
    return @(pFirst->pArr(i))
    
   EndIf
   
  Next
  
    EndIf
    
End Function

function TLIST.getLast() as any ptr
    
    if pLast then
  
  for i as Long = 31 to 0 step -1
   
   if bit(pLast->bFill , i) then
    
    return @(pLast->pArr(i))
    
   EndIf
   
  Next
  
    EndIf
    
End Function

function TLIST.getPrev() as any ptr
    
    if pCurent.pRoot then
  
  dim as TNODE ptr pRootNode = any
  
  dim iStartIndex as ULong = any
  
  if iCurentIndex = 0 then
   
   pRootNode = cast(TNODE ptr , pCurent.pRoot)->pNext
   
   iStartIndex = 32
   
  else
   
   iStartIndex = iCurentIndex
   
   pRootNode = cast(TNODE ptr , pCurent.pRoot)
   
  EndIf
  
  do
   
   for i as Long = 31 to iStartIndex-1 step-1
    
    if bit(pRootNode->bFill , i) then
     
     pCurent.pRoot = cast(T_NODE ptr , pRootNode)
     
     pCurent.p = pRootNode->pArr(i).p
     
     iCurentIndex = i
     
     return pCurent.pRoot
     
    EndIf
    
   Next
   
   iStartIndex = 0
   
   pRootNode = pRootNode->pNext
   
  loop while pRootNode
  
    endif
    
End Function

function TLIST.getNext() as any ptr
    
    if pCurent.pRoot then
  
  dim as TNODE ptr pRootNode = any
  
  dim iStartIndex as ULong = any
  
  if iCurentIndex = 31 then
   
   pRootNode = cast(TNODE ptr , pCurent.pRoot)->pNext
   
   iStartIndex = -1
   
  else
   
   iStartIndex = iCurentIndex
   
   pRootNode = cast(TNODE ptr , pCurent.pRoot)
   
  EndIf
  
  do
   
   for i as Long = iStartIndex+1 to 31
    
    if bit(pRootNode->bFill , i) then
     
     pCurent.pRoot = cast(T_NODE ptr , pRootNode)
     
     pCurent.p = pRootNode->pArr(i).p
     
     iCurentIndex = i
     
     return pCurent.pRoot
     
    EndIf
    
   Next
   
   iStartIndex = 0
   
   pRootNode = pRootNode->pNext
   
  loop while pRootNode
  
    endif
    
End Function

function TLIST.getValue() as tData
    
    if pCurent.pRoot then return pCurent.p
    
End Function

sub TLIST.setValue(pData as tData)
    
    if pCurent.pRoot then pCurent.p = pData
    
End sub

sub TLIST.resetList()
    
    if pFirst then
  
  for i as Long = 0 to 31
   
   if bit(pFirst->bFill , i) then
    
    iCurentIndex = i
    
    pCurent.pRoot = cast(T_NODE ptr,pFirst)
    
    pCurent.p = pFirst->pArr(i).p
    
    exit for
    
   EndIf
   
  Next
  
    EndIf
    
End Sub

var t = timer
'
dim p as TLIST

for i as long = 0 to 10000000
    
    p.add(i)
    
Next

p.resetList()

do
    
    var v = p.getValue()
    
    '? "value" , V
    
Loop while p.getNext()

? timer -t
sleep


А это пуриковский код:

Код
OpenConsole()
StartTime.q = ElapsedMilliseconds()

NewList MyList()

For i=0 To 10000000

  AddElement(MyList())
  
  MyList() = i

Next

ResetList(MyList())
While NextElement(MyList())
f = MyList()
Wend

Print(Str(ElapsedMilliseconds() - StartTime))


Удаление делается очень просто. Для первой и последней ячейки массива (их я напомню 32 для каждого Node ) просто обнуляем нужный бит в переменной bFill. Реализация построена так , что будет пропускать эти ячейки. Для других ячеек, просто сдвигать данные в цикле. Если окажется так , что все ячейки массива пустые , то Node так же удаляем.
Что касается вставки. Если нужно вставлять в начало или в конец любого массива , то тут просто создаем новый Node c новым массивом , записываем в нулевую ячейку данные и устанавливаем его текущим. И так же конечно связываем новый Node c предыдущим и следующим Node.

Если нужно вставить в середину массива... , то покажу на примере:

1 Node и его массив {0,1,2,3,4,5,6,7.....}
2 Node и его массив {0,1,2,3,4,5,6,7.....}

Нужно вставить данные после 4 ячейки 1 Node. Должно получится так:

1 Node и его массив {0,1,2,3,4,new,5,6,7.....} Сначала копируем последнюю ячейку в новый массив, потом просто переносим остальные ячейки вперед в цикле.
new Node и его массив {31,.....} <- сюда копируем последнюю ячейку из первого массива.
2 Node и его массив {0, 1,2,3,4,5,6,7.....} здесь ничего не трогаем

или так будет быстрее (в общем определять какая ячейка ближе и где меньше данных переносить):
new Node и его массив {0,.....} <- сюда копируем первую ячейку из первого массива.
1 Node и его массив {1,2,3,4,new,5,6,7.....} Сначала копируем первую ячейку в новый массив, потом просто переносим остальные ячейки назад в цикле.
2 Node и его массив {0, 1,2,3,4,5,6,7.....} здесь ничего не трогаем

Ну и конечно нужно будет связать Nodes между собой.

Наверняка , при написании , могут возникнуть и другие идеи, я лишь озвучил ту, которая первая пришла в голову.


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
haavДата: Понедельник, 17.01.2022, 22:16 | Сообщение # 20
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Если кто-то будет тестировать , не забываем в пурике отключать дебаггер , а в FB компилировать просто без опций

Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
haavДата: Среда, 19.01.2022, 13:40 | Сообщение # 21
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Нет , все таки пуриковский лист какая-то фантастика. Ведь по сути у них скорость:

1) вставка примерно как у связанного списка
2) добавление быстрее чем в связанных списках
3) удаление как в связанных списках
4) доступ как у массивов по индексу. Понятно , что данные не лежат упорядочено как в массиве , но скорость получения данных сопоставима!

Как Фреду удалось то , что кажется невозможным? Ему что , код списков инопланетяне подсказали?


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
WQДата: Среда, 19.01.2022, 20:56 | Сообщение # 22
Полковник
Группа: Проверенные
Сообщений: 215
Репутация: 7
Статус: Offline
haav

Вроде списки из этой темы довольно быстрые, по крайней мере по сравнению с другими примерами на freebasic

https://www.freebasic.net/forum....p260519
 
haavДата: Среда, 19.01.2022, 21:34 | Сообщение # 23
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата WQ ()
Вроде списки из этой темы довольно быстрые, по крайней мере по сравнению с другими примерами на freebasic

Примеры 2 и 3 созданы по классической схеме, то есть добавление , удаление , вставка будут более менее быстрыми, если заранее известен указатель. В пурике есть мгновенная индексация и можно очень быстро например изменить или удалить каждый 10 элемент от начала. Кроме того , добавление в конец в пурике раза в 1.5 быстрее. Конечно , если не нужна частая вставка и удаление , а просто нужно заполнить и получать доступ , то вообще можно использовать вектор из моих контейнеров , он по скорости добавления обгонит пуриковский список почти в 2 раза. Но если нужна частая вставка и удаление (особенно вначале или в середине) , то тут по времени вектор окажется в глубокой заднице.

Что касается 1 примера , то достаточно только посмотреть на этот отрывок кода:


Код
function simple_list.find(value as data_type) as integer
   for i as integer = 0 to ubound(myData)
      if myData(i) = value then return i
   next
   return -1 'not found
end function

как сразу станет все понятно. Эта обычный линейный перебор. Уж лучше тогда деревья или хеш таблица. Списки не для того , чтобы линейно перебирать всю коллекцию в поисках ключа. Конечно для не критических участков и так сойдет.
Мне на самом деле больше интересно , как Фред сумел скрестить быстроту доступа массива и скорость добавления\вставки\удаления связанных списков в одно целое.


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
haavДата: Четверг, 20.01.2022, 08:24 | Сообщение # 24
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Блин , вот ведь я дурень. Нет никаких чудес и нет никакого мгновенного доступа у пуриковских списков. Я уж думал , что такое реально возможно с помощью какого нибудь хитрого индексирования. Переоценил я человеческие возможности. Все как всегда , просто были удобные примеры , да и я стормозил. Если же реально сделать постоянные перемещения по индексам , то список ведет себя ожидаемо с линейной зависимостью. Вот простейший пример в котором просто список заполняется миллионом элементов , а потом при получении всего то 10000 значений из разных индексов , список тратит более 10 секунд:

Код
Dim m(1)
m(0) = 421111
m(1) = 763000

NewList MyList()

For i=0 To 1000000
  AddElement(MyList())
  MyList() = i
Next

StartTime.q = ElapsedMilliseconds()

For i=0 To 5000
  For j = 0 To 1
    SelectElement(MyList() , m(j))
    p = MyList()
 Next
Next

MessageRequester("" , Str(ElapsedMilliseconds() - StartTime))

Ну вот в общем-то и все , дальнейшие ковыряния уже не интересны.


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
WQДата: Суббота, 26.03.2022, 23:50 | Сообщение # 25
Полковник
Группа: Проверенные
Сообщений: 215
Репутация: 7
Статус: Offline
haav

У HashTable нет возможности обхода всей таблицы?
 
laserДата: Воскресенье, 27.03.2022, 01:45 | Сообщение # 26
Лейтенант
Группа: Пользователи
Сообщений: 57
Репутация: -46
Статус: Offline
Цитата haav ()
нет никакого мгновенного доступа у пуриковских списков. Я уж думал , что такое реально возможно с помощью какого нибудь хитрого индексирования.
В PB стандартный [url=https://ru.wikipedia.org/wiki/Связный_список#Двусвязный_список_(двунаправленный_связный_список)]двусвязный список[/url].
В каждом элементе храниться ссылка на предыдущий и следующий элемент. Кроме того в списке хранится ссылка на начальный, текущий и конечный элемент. Чтобы найти элемент нужно пройтись по списку. Если выбирать элементы, близкие к начальному, текущему или конечному, поиск производит очень быстро.
Код
DisableDebugger
Dim m(3)
m(0) = 200
m(1) = 100
m(2) = 1000000-100
m(3) = 1000000-200

NewList MyList()

For i=0 To 1000000
  AddElement(MyList())
  MyList() = i
Next

StartTime.q = ElapsedMilliseconds()

For i=0 To 5000
  For j = 0 To 3
    SelectElement(MyList() , m(j))
    p = MyList()
Next
Next

MessageRequester("" , Str(ElapsedMilliseconds() - StartTime))
Также последовательной перебор списка производится быстро.
Код
DisableDebugger

NewList MyList()

For i=0 To 1000000
  AddElement(MyList())
  MyList() = i
Next

StartTime.q = ElapsedMilliseconds()

ForEach MyList()
  p = MyList()
Next

MessageRequester("" , Str(ElapsedMilliseconds() - StartTime))


Сообщение отредактировал laser - Воскресенье, 27.03.2022, 01:46
 
haavДата: Воскресенье, 27.03.2022, 07:31 | Сообщение # 27
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата WQ ()
У HashTable нет возможности обхода всей таблицы?


Я даже не думал , что это может быть нужно. Но вообще это не проблема , ты всегда можешь добавить процедуру перечисления. Вот пример:

Код
#include "HashTable.bi"

MHashTemplate(Zstring , Zstring)

Dim As THASHTABLEzstringzstring Ptr pTable = New THASHTABLEzstringzstring

sub EnumTable(pTable as THASHTABLEzstringzstring Ptr)
    For i As Long = 0 To pTable->iSize
  If pTable->pArray[i].pszKey Then
   If pTable->pArray[i].iFdelete = 0 Then
    ? *(pTable->pArray[i].pszValue)
   Endif
   If pTable->pArray[i].pList Then
    Dim As TLISTzstringzstring Ptr pTemp
    pTemp = pTable->pArray[i].pList->pFirst
    While pTemp
     ? *(pTemp->pszValue)
     pTemp = pTemp->P
    Wend
   Endif
  Endif
    Next
End Sub

pTable->insert("Key1" , "Value1")
pTable->insert("Key2" , "Value2")
EnumTable(pTable)
pTable->cleartable()
pTable->freetable()
Sleep


Цитата laser ()
В каждом элементе храниться ссылка на предыдущий и следующий элемент. Кроме того в списке хранится ссылка на начальный, текущий и конечный элемент. Чтобы найти элемент нужно пройтись по списку. Если выбирать элементы, близкие к начальному, текущему или конечному, поиск производит очень быстро.


Да , я это понял , но не сразу. Индексацию в своем списке я переписал тоже по этому принципу.

Кстати laser , в линуксе Фред сделал многопоточность для Gui? Для w9 я нашел способ использовать многопоточность (пример ниже). Если многопоточности нет , то можно ее прикрутить как в примере ниже? Если лень запускать FB код , то вкратце это работает так: в Textgadget меняется текст с помощью 2 дополнительных потоков и при клике мыши по гаджету текст так же меняется. То есть получается текст меняется в 3 потоках и не конфликтует.

Пример:

Код

#include "gtk/gtk.bi"
#inclib "gthread-2.0"
g_thread_init(0)
gdk_threads_init()
#include "window9.bi"

Declare Function thSub Cdecl(p As Integer) As Any Ptr

gdk_threads_enter()

Dim As Integer Event
Dim As GError Ptr pErr

Dim Shared As String sValue

Openwindow("",10,10,100,100)
Textgadget(1,10,40,100,20,"textgadget")

If g_thread_create(Cast(Any Ptr ,@thSub()), Cast(Any Ptr ,1), False, @pErr) = 0 Then
    Print "Failed to create thread 1", pErr->message
    End
Endif

If g_thread_create(Cast(Any Ptr ,@thSub()), Cast(Any Ptr ,2), False, @pErr) = 0 Then
    Print "Failed to create thread 2", pErr->message
    End
Endif

Do
    Event=Waitevent()
    If Event= Eventclose Then End
    If Event=Eventgadget Then
  Select Case Eventnumber
   Case 1
    sValue = "main thread"
    Setgadgettext(1,sValue)
  End Select
    Endif
Loop

gdk_threads_leave()

End

Function thSub Cdecl(p As Integer) As Any Ptr
    Do
  Sleep(Rnd*1000)
  gdk_threads_enter()
  If p = 1 Then
   sValue = "thread 1"
  Else
   sValue = "thread 2"
  Endif
  Setgadgettext(1 , sValue)
  gdk_flush()
  gdk_threads_leave()
    Loop
    Return 0
End Function


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
haavДата: Воскресенье, 27.03.2022, 09:55 | Сообщение # 28
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Че-то какая-то ерунда творится с редактированием сообщений. После редактирования все теги путаются. Уже два раза редактировал и кое-как сумел донести то , что хотел. Уже не рискнул дополнительно вносить в прошлое сообщение текущие строчки . Лучше отдельно , а то опять весь текст исправлять в отдельном редакторе. Возможно это из-за индексации в коде , вроде pArray[i].pszKey.

Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
laserДата: Воскресенье, 27.03.2022, 17:21 | Сообщение # 29
Лейтенант
Группа: Пользователи
Сообщений: 57
Репутация: -46
Статус: Offline
Цитата haav ()
в линуксе Фред сделал многопоточность для Gui?
Нет. Только в лине 3 подсистемы (gtk2, gtk3 и qt). В маке свой GUI. Это надо тестить много платформ и подсистем на совместимость с многопоточностью.
Можно сделать проще и на 100% рабочим на всех платформах.
Код
CompilerIf #PB_Compiler_Thread=0
  CompilerError "Please enable treadsafe"
CompilerEndIf

Enumeration #PB_Event_FirstCustomValue
  #EventGadgetUpdate
EndEnumeration

  
Procedure Thread(Value)
  For i=1 To 10
    PostEvent(#EventGadgetUpdate, 0, 2, 0, i)
    Delay(1000)
    PostEvent(#EventGadgetUpdate, 0, 3, 0, i*10)
    Delay(1000)
  Next
  
  PostEvent(#PB_Event_CloseWindow, 0, 0) ; Закрываем форточку а вместе с ней прогу.
EndProcedure

OpenWindow(0, 200, 200, 100, 100, "PostEvent")
TextGadget(2, 10, 10, 180, 20, "")
TextGadget(3, 10, 30, 180, 20, "")

CreateThread(@Thread(), 0)

Repeat
  Event = WaitWindowEvent()
  
  Select Event
    Case #EventGadgetUpdate
      Gadget = EventGadget()
      If IsGadget(Gadget)
        SetGadgetText(Gadget, Str(EventData()))
      EndIf
  EndSelect
  
Until Event = #PB_Event_CloseWindow
Из потока отправляться событие с номером гаджета и данными. В основном потоке записывается в гаджет.

Цитата haav ()
То есть получается текст меняется в 3 потоках и не конфликтует.
Точно не конфликтует? В коде глобальная переменная sValue общая для всех потоков. Глюк будет, но через случайное время.
Сделай переменную локальной или поточной (аналог Threaded в PB).


Сообщение отредактировал laser - Воскресенье, 27.03.2022, 17:22
 
haavДата: Воскресенье, 27.03.2022, 18:22 | Сообщение # 30
Генералиссимус
Группа: Администраторы
Сообщений: 1361
Репутация: 49
Статус: Offline
Цитата laser ()
Точно не конфликтует? В коде глобальная переменная sValue общая для всех потоков. Глюк будет, но через случайное время.


Я конечно не уверен на 100% , но вроде эти штуки:

gdk_threads_enter , gdk_threads_leave

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

Цитата laser ()
Из потока отправляться событие с номером гаджета и данными. В основном потоке записывается в гаджет.


Наверное именно для PostEvent (а может и не только для нее) все таки синхронизация внутренне выполняется.


Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
Форум » Freebasic » Вопросы по языку FreeBasic » Тестирование разных контейнеров и другая болтовня (тестирование хеш таблиц , map и пр.)
  • Страница 2 из 4
  • «
  • 1
  • 2
  • 3
  • 4
  • »
Поиск: