fxm wrote:ThreadPooling' is not adapted to work piecemeal (PoolingSubmit : PoolingWait : PoolingSubmit : PoolingWait ...) like 'ThreadInitThenMultiStart' (ThreadInit : ThreadStart : ThreadWait : ThreadInit : ThreadStart : ThreadWait ...) due to the principle chosen in 'PoolingWait' (stopping then restarting the internal thread).
But from a sequence of 10 'PoolingSubmit' followed by 1 'PoolingWait', the performance becomes equivalent to 10 'ThreadInit: ThreadStart: ThreadWait', then a little better after.
I modified 'PoolingWait' to no longer restart the internal thread, by adding a mutex only (_mutex3).
Now, the 'ThreadPooling' results are more similar with 'ThreadInitThenMultiStart' and even a little better when filling in the internal queue with several submissions before request 'PoolingWait'.
- Testing with the current version of 'ThreadPooling' (worst case with an empty user procedure):
Code: Select all
Type ThreadInitThenMultiStart
Public:
Declare Constructor()
Declare Sub ThreadInit(Byval pThread As Function(Byval As Any Ptr) As String, Byval p As Any Ptr = 0)
Declare Sub ThreadStart()
Declare Sub ThreadStart(Byval p As Any Ptr)
Declare Function ThreadWait() As String
Declare Property ThreadState() As Ubyte
Declare Destructor()
Private:
Dim As Function(Byval p As Any Ptr) As String _pThread
Dim As Any Ptr _p
Dim As Any Ptr _mutex1
Dim As Any Ptr _mutex2
Dim As Any Ptr _mutex3
Dim As Any Ptr _pt
Dim As Byte _end
Dim As String _returnF
Dim As Ubyte _state
Declare Static Sub _Thread(Byval p As Any Ptr)
End Type
Constructor ThreadInitThenMultiStart()
This._mutex1 = Mutexcreate()
Mutexlock(This._mutex1)
This._mutex2 = Mutexcreate()
Mutexlock(This._mutex2)
This._mutex3 = Mutexcreate()
Mutexlock(This._mutex3)
End Constructor
Sub ThreadInitThenMultiStart.ThreadInit(Byval pThread As Function(Byval As Any Ptr) As String, Byval p As Any Ptr = 0)
This._pThread = pThread
This._p = p
If This._pt = 0 Then
This._pt= Threadcreate(@ThreadInitThenMultiStart._Thread, @This)
Mutexunlock(This._mutex3)
This._state = 1
End If
End Sub
Sub ThreadInitThenMultiStart.ThreadStart()
Mutexlock(This._mutex3)
Mutexunlock(This._mutex1)
End Sub
Sub ThreadInitThenMultiStart.ThreadStart(Byval p As Any Ptr)
Mutexlock(This._mutex3)
This._p = p
Mutexunlock(This._mutex1)
End Sub
Function ThreadInitThenMultiStart.ThreadWait() As String
Mutexlock(This._mutex2)
Mutexunlock(This._mutex3)
This._state = 1
Return This._returnF
End Function
Property ThreadInitThenMultiStart.ThreadState() As Ubyte
Return This._state
End Property
Sub ThreadInitThenMultiStart._Thread(Byval p As Any Ptr)
Dim As ThreadInitThenMultiStart Ptr pThis = p
Do
Mutexlock(pThis->_mutex1)
If pThis->_end = 1 Then Exit Sub
pThis->_state = 2
pThis->_returnF = pThis->_pThread(pThis->_p)
pThis->_state = 4
Mutexunlock(pThis->_mutex2)
Loop
End Sub
Destructor ThreadInitThenMultiStart()
If This._pt > 0 Then
This._end = 1
Mutexunlock(This._mutex1)
.ThreadWait(This._pt)
End If
Mutexdestroy(This._mutex1)
Mutexdestroy(This._mutex2)
Mutexdestroy(This._mutex3)
End Destructor
'---------------------------------------------------
Type ThreadPooling
Public:
Declare Constructor()
Declare Sub PoolingSubmit(Byval pThread As Function(Byval As Any Ptr) As String, Byval p As Any Ptr = 0)
Declare Sub PoolingWait()
Declare Sub PoolingWait(values() As String)
Declare Property PoolingState() As Ubyte
Declare Destructor()
Private:
Dim As Function(Byval p As Any Ptr) As String _pThread0
Dim As Any Ptr _p0
Dim As Function(Byval p As Any Ptr) As String _pThread(Any)
Dim As Any Ptr _p(Any)
Dim As Any Ptr _mutex1
Dim As Any Ptr _mutex2
Dim As Any Ptr _pt
Dim As Byte _end
Dim As String _returnF(Any)
Dim As Ubyte _state
Declare Static Sub _Thread(Byval p As Any Ptr)
End Type
Constructor ThreadPooling()
Redim This._pThread(0)
Redim This._p(0)
Redim This._returnF(0)
This._mutex1 = Mutexcreate()
This._mutex2 = Mutexcreate()
Mutexlock(This._mutex2)
This._pt= Threadcreate(@ThreadPooling._Thread, @This)
End Constructor
Sub ThreadPooling.PoolingSubmit(Byval pThread As Function(Byval As Any Ptr) As String, Byval p As Any Ptr = 0)
Mutexlock(This._mutex1)
If Ubound(This._pThread) = 0 Then
Mutexunlock(This._mutex2)
End If
Redim Preserve This._pThread(Ubound(This._pThread) + 1)
This._pThread(Ubound(This._pThread)) = pThread
Redim Preserve This._p(Ubound(This._p) + 1)
This._p(Ubound(This._p)) = p
Mutexunlock(This._mutex1)
This._state = 1
End Sub
Sub ThreadPooling.PoolingWait()
This._end = 1
Mutexunlock(This._mutex2)
.ThreadWait(This._pt)
This._end = 0
Redim This._returnF(0)
This._state = 0
This._pt= Threadcreate(@ThreadPooling._Thread, @This)
End Sub
Sub ThreadPooling.PoolingWait(values() As String)
This._end = 1
Mutexunlock(This._mutex2)
.ThreadWait(This._pt)
This._end = 0
If Ubound(This._returnF) > 0 Then
Redim values(1 To Ubound(This._returnF))
For I As Integer = 1 To Ubound(This._returnF)
values(I) = This._returnF(I)
Next I
Redim This._returnF(0)
Else
Erase values
End If
This._state = 0
This._pt= Threadcreate(@ThreadPooling._Thread, @This)
End Sub
Property ThreadPooling.PoolingState() As Ubyte
Return This._state
End Property
Sub ThreadPooling._Thread(Byval p As Any Ptr)
Dim As ThreadPooling Ptr pThis = p
Do
Mutexlock(pThis->_mutex1)
While Ubound(pThis->_pThread) = 0
Mutexunlock(pThis->_mutex1)
pThis->_state = 4
Mutexlock(pThis->_mutex2)
If pThis->_end = 1 And Ubound(pThis->_pThread) = 0 Then Exit Sub
Mutexlock(pThis->_mutex1)
Wend
pThis->_pThread0 = pThis->_pThread(1)
pThis->_p0 = pThis->_p(1)
For I As Integer = 2 To Ubound(pThis->_pThread)
pThis->_pThread(I - 1) = pThis->_pThread(I)
pThis->_p(I - 1) = pThis->_p(I)
Next I
Redim Preserve pThis->_pThread(Ubound(pThis->_pThread) - 1)
Redim Preserve pThis->_p(Ubound(pThis->_p) - 1)
Mutexunlock(pThis->_mutex1)
Redim Preserve pThis->_ReturnF(Ubound(pThis->_returnF) + 1)
pThis->_state = 2
pThis->_returnF(Ubound(pThis->_returnF)) = pThis->_pThread0(pThis->_p0)
Loop
End Sub
Destructor ThreadPooling()
This._end = 1
Mutexunlock(This._mutex2)
.ThreadWait(This._pt)
Mutexdestroy(This._mutex1)
Mutexdestroy(This._mutex2)
End Destructor
'---------------------------------------------------
Function UserCode (Byval p As Any Ptr) As String
Return ""
End Function
Dim As ThreadInitThenMultiStart ta
Dim As ThreadPooling tb
Dim As Double t
Print "Sequence of 10000 [ta.ThreadInit(@UserCode):ta.ThreadStart():ta.ThreadWait()]"
t = Timer
For I As Integer = 1 To 10000
ta.ThreadInit(@UserCode)
ta.ThreadStart()
ta.ThreadWait()
Next I
t = Timer - t
Print t; " s"
Print
Print "Sequence of 10000 [tb.PoolingSubmit(@UserCode):tb.PoolingWait()]"
t = Timer
For I As Integer = 1 To 10000
tb.PoolingSubmit(@UserCode)
tb.PoolingWait()
Next I
t = Timer - t
Print t; " s"
Print
Print "Sequence of 10000 [tb.PoolingSubmit(@UserCode)] ended by 1 [tb.PoolingWait()]
t = Timer
For I As Integer = 1 To 10000
tb.PoolingSubmit(@UserCode)
Next I
tb.PoolingWait()
t = Timer - t
Print t; " s"
Sleep
Sequence of 10000 [ta.ThreadInit(@UserCode):ta.ThreadStart():ta.ThreadWait()]
0.1496771000024921 s
Sequence of 10000 [tb.PoolingSubmit(@UserCode):tb.PoolingWait()]
1.224177599985183 s
Sequence of 10000 [tb.PoolingSubmit(@UserCode)] ended by 1 [tb.PoolingWait()]
0.1206457999761597 s
- Testing with the
new version of 'ThreadPooling' (worst case with an empty user procedure):
Code: Select all
Type ThreadInitThenMultiStart
Public:
Declare Constructor()
Declare Sub ThreadInit(Byval pThread As Function(Byval As Any Ptr) As String, Byval p As Any Ptr = 0)
Declare Sub ThreadStart()
Declare Sub ThreadStart(Byval p As Any Ptr)
Declare Function ThreadWait() As String
Declare Property ThreadState() As Ubyte
Declare Destructor()
Private:
Dim As Function(Byval p As Any Ptr) As String _pThread
Dim As Any Ptr _p
Dim As Any Ptr _mutex1
Dim As Any Ptr _mutex2
Dim As Any Ptr _mutex3
Dim As Any Ptr _pt
Dim As Byte _end
Dim As String _returnF
Dim As Ubyte _state
Declare Static Sub _Thread(Byval p As Any Ptr)
End Type
Constructor ThreadInitThenMultiStart()
This._mutex1 = Mutexcreate()
Mutexlock(This._mutex1)
This._mutex2 = Mutexcreate()
Mutexlock(This._mutex2)
This._mutex3 = Mutexcreate()
Mutexlock(This._mutex3)
End Constructor
Sub ThreadInitThenMultiStart.ThreadInit(Byval pThread As Function(Byval As Any Ptr) As String, Byval p As Any Ptr = 0)
This._pThread = pThread
This._p = p
If This._pt = 0 Then
This._pt= Threadcreate(@ThreadInitThenMultiStart._Thread, @This)
Mutexunlock(This._mutex3)
This._state = 1
End If
End Sub
Sub ThreadInitThenMultiStart.ThreadStart()
Mutexlock(This._mutex3)
Mutexunlock(This._mutex1)
End Sub
Sub ThreadInitThenMultiStart.ThreadStart(Byval p As Any Ptr)
Mutexlock(This._mutex3)
This._p = p
Mutexunlock(This._mutex1)
End Sub
Function ThreadInitThenMultiStart.ThreadWait() As String
Mutexlock(This._mutex2)
Mutexunlock(This._mutex3)
This._state = 1
Return This._returnF
End Function
Property ThreadInitThenMultiStart.ThreadState() As Ubyte
Return This._state
End Property
Sub ThreadInitThenMultiStart._Thread(Byval p As Any Ptr)
Dim As ThreadInitThenMultiStart Ptr pThis = p
Do
Mutexlock(pThis->_mutex1)
If pThis->_end = 1 Then Exit Sub
pThis->_state = 2
pThis->_returnF = pThis->_pThread(pThis->_p)
pThis->_state = 4
Mutexunlock(pThis->_mutex2)
Loop
End Sub
Destructor ThreadInitThenMultiStart()
If This._pt > 0 Then
This._end = 1
Mutexunlock(This._mutex1)
.ThreadWait(This._pt)
End If
Mutexdestroy(This._mutex1)
Mutexdestroy(This._mutex2)
Mutexdestroy(This._mutex3)
End Destructor
'---------------------------------------------------
#include once "crt/string.bi"
Type ThreadPooling '' new version
Public:
Declare Constructor()
Declare Sub PoolingSubmit(Byval pThread As Function(Byval As Any Ptr) As String, Byval p As Any Ptr = 0)
Declare Sub PoolingWait()
Declare Sub PoolingWait(values() As String)
Declare Property PoolingState() As Ubyte
Declare Destructor()
Private:
Dim As Function(Byval p As Any Ptr) As String _pThread0
Dim As Any Ptr _p0
Dim As Function(Byval p As Any Ptr) As String _pThread(Any)
Dim As Any Ptr _p(Any)
Dim As Any Ptr _mutex1
Dim As Any Ptr _mutex2
Dim As Any Ptr _mutex3
Dim As Any Ptr _pt
Dim As Byte _end
Dim As String _returnF(Any)
Dim As Ubyte _state
Declare Static Sub _Thread(Byval p As Any Ptr)
End Type
Constructor ThreadPooling()
Redim This._pThread(0)
Redim This._p(0)
Redim This._returnF(0)
This._mutex1 = Mutexcreate()
This._mutex2 = Mutexcreate()
Mutexlock(This._mutex2)
This._mutex3 = Mutexcreate()
Mutexlock(This._mutex3)
This._pt= Threadcreate(@ThreadPooling._Thread, @This)
End Constructor
Sub ThreadPooling.PoolingSubmit(Byval pThread As Function(Byval As Any Ptr) As String, Byval p As Any Ptr = 0)
Mutexlock(This._mutex1)
If Ubound(This._pThread) = 0 Then
Mutexunlock(This._mutex2)
End If
Redim Preserve This._pThread(Ubound(This._pThread) + 1)
This._pThread(Ubound(This._pThread)) = pThread
Redim Preserve This._p(Ubound(This._p) + 1)
This._p(Ubound(This._p)) = p
Mutexunlock(This._mutex1)
This._state = 1
End Sub
Sub ThreadPooling.PoolingWait()
Mutexlock(This._mutex3)
Redim This._returnF(0)
This._state = 0
Mutexunlock(This._mutex3)
End Sub
Sub ThreadPooling.PoolingWait(values() As String)
Mutexlock(This._mutex3)
If Ubound(This._returnF) > 0 Then
Redim values(1 To Ubound(This._returnF))
For I As Integer = 1 To Ubound(This._returnF)
values(I) = This._returnF(I)
Next I
Redim This._returnF(0)
Else
Erase values
End If
This._state = 0
Mutexunlock(This._mutex3)
End Sub
Property ThreadPooling.PoolingState() As Ubyte
Return This._state
End Property
Sub ThreadPooling._Thread(Byval p As Any Ptr)
Dim As ThreadPooling Ptr pThis = p
Do
Mutexlock(pThis->_mutex1)
While Ubound(pThis->_pThread) = 0
Mutexunlock(pThis->_mutex1)
Mutexunlock(pThis->_mutex3)
pThis->_state = 4
Mutexlock(pThis->_mutex2)
If pThis->_end = 1 And Ubound(pThis->_pThread) = 0 Then Exit Sub
Mutexlock(pThis->_mutex3)
Mutexlock(pThis->_mutex1)
Wend
pThis->_pThread0 = pThis->_pThread(1)
pThis->_p0 = pThis->_p(1)
If Ubound(pThis->_pThread) > 1 Then
memmove(@pThis->_pThread(1), @pThis->_pThread(2), (Ubound(pThis->_pThread) - 1) * Sizeof(pThis->_pThread))
memmove(@pThis->_p(1), @pThis->_p(2), (Ubound(pThis->_p) - 1) * Sizeof(pThis->_p))
End If
Redim Preserve pThis->_pThread(Ubound(pThis->_pThread) - 1)
Redim Preserve pThis->_p(Ubound(pThis->_p) - 1)
Mutexunlock(pThis->_mutex1)
Redim Preserve pThis->_ReturnF(Ubound(pThis->_returnF) + 1)
pThis->_state = 2
pThis->_returnF(Ubound(pThis->_returnF)) = pThis->_pThread0(pThis->_p0)
Loop
End Sub
Destructor ThreadPooling()
This._end = 1
Mutexunlock(This._mutex2)
.ThreadWait(This._pt)
Mutexdestroy(This._mutex1)
Mutexdestroy(This._mutex2)
Mutexdestroy(This._mutex3)
End Destructor
'---------------------------------------------------
Function UserCode (Byval p As Any Ptr) As String
Return ""
End Function
Dim As ThreadInitThenMultiStart ta
Dim As ThreadPooling tb
Dim As Double t
Print "Sequence of 10000 [ta.ThreadInit(@UserCode):ta.ThreadStart():ta.ThreadWait()]"
t = Timer
For I As Integer = 1 To 10000
ta.ThreadInit(@UserCode)
ta.ThreadStart()
ta.ThreadWait()
Next I
t = Timer - t
Print t; " s"
Print
Print "Sequence of 10000 [tb.PoolingSubmit(@UserCode):tb.PoolingWait()]"
t = Timer
For I As Integer = 1 To 10000
tb.PoolingSubmit(@UserCode)
tb.PoolingWait()
Next I
t = Timer - t
Print t; " s"
Print
Print "Sequence of 10000 [tb.PoolingSubmit(@UserCode)] ended by 1 [tb.PoolingWait()]
t = Timer
For I As Integer = 1 To 10000
tb.PoolingSubmit(@UserCode)
Next I
tb.PoolingWait()
t = Timer - t
Print t; " s"
Sleep
Sequence of 10000 [ta.ThreadInit(@UserCode):ta.ThreadStart():ta.ThreadWait()]
0.1384070999896494 s
Sequence of 10000 [tb.PoolingSubmit(@UserCode):tb.PoolingWait()]
0.152863899992866 s
Sequence of 10000 [tb.PoolingSubmit(@UserCode)] ended by 1 [tb.PoolingWait()]
0.1222732999936227 s