|
-
Nov 1st, 2024, 10:13 AM
#1
Thread Starter
Frenzied Member
Pulling from a queue using multiple tasks
I need some help trying to accomplish something. I have a concurrentqueue defined in my program. Items get added to the queue in a sporadic fashion. It could be empty for a couple hours, then get 50-60 items added to it within seconds. I want to have multiple tasks (5 for example) that "watch" the queue for when items are added, then dequeue the items & perform a process on each one. So while the queue is empty, the tasks are idle. But if 20 items get added then the tasks "see" that there items in the queue & they dequeue & process the items, 5 at a time, until all 20 are gone. Then the tasks are idle again until items are added the the queue again. This gets repeated over & over, while the program is running. I'm not sure how to set this up so that the tasks start up when items are added. Do I need to use a loop to constantly be checking if the queue has items? That seems inefficient to me. Any help would be appreciated. Thanks...
-
Nov 1st, 2024, 10:41 AM
#2
Re: Pulling from a queue using multiple tasks
Maybe this will give you some ideas,
Code:
Public Class Form1
Private IdleTime As Integer = 250 'how long to wait between Q checks
Private IdleCheck As New Threading.ManualResetEvent(False)
Private MyQ As New Concurrent.ConcurrentQueue(Of String)
Private MyTasks As New List(Of Task)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For x As Integer = 1 To 5 'start five tasks
Dim tsk As Task = Task.Run(Sub() ProcMyQ())
MyTasks.Add(tsk)
Next
End Sub
Private Sub ProcMyQ()
Do While Not IdleCheck.WaitOne(IdleTime)
Do While MyQ.Count > 0
Dim s As String = ""
If MyQ.TryDequeue(s) Then
'process item
Debug.WriteLine(s)
End If
Loop
Loop
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For x As Integer = 1 To 100
MyQ.Enqueue(x.ToString)
Next
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
IdleCheck.Set() 'stop the tasks
End Sub
End Class
-
Nov 1st, 2024, 10:43 AM
#3
Re: Pulling from a queue using multiple tasks
-
Nov 2nd, 2024, 04:01 PM
#4
Member
Re: Pulling from a queue using multiple tasks
You don’t have to keep looping through the queue, which can waste resources. Instead, I recommend using a BlockingCollection instead of ConcurrentQueue. It’s super handy because it blocks the tasks when there are no items and wakes them up when something gets added. You can set up multiple tasks that listen for items in the collection, and when an item is added, they just grab it and process it. I’ve used this approach in a similar situation, and it worked great for managing bursts of data without keeping everything in a constant check. Just add items to the BlockingCollection, and your tasks will handle the rest.
-
Nov 4th, 2024, 11:26 AM
#5
Thread Starter
Frenzied Member
Re: Pulling from a queue using multiple tasks
 Originally Posted by Napstore
You don’t have to keep looping through the queue, which can waste resources. Instead, I recommend using a BlockingCollection instead of ConcurrentQueue. It’s super handy because it blocks the tasks when there are no items and wakes them up when something gets added. You can set up multiple tasks that listen for items in the collection, and when an item is added, they just grab it and process it. I’ve used this approach in a similar situation, and it worked great for managing bursts of data without keeping everything in a constant check. Just add items to the BlockingCollection, and your tasks will handle the rest.
Thanks, that sounds exactly like what I need. Any chance you can post a quick example of how to set it up?
-
Nov 4th, 2024, 11:38 AM
#6
Re: Pulling from a queue using multiple tasks
 Originally Posted by nbrege
Thanks, that sounds exactly like what I need. Any chance you can post a quick example of how to set it up?
Code:
Public Class Form1
Private MyBC As New Concurrent.BlockingCollection(Of String)
Private MyTasks As New List(Of Task)
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
MyBC.CompleteAdding()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For x As Integer = 1 To 5 'start five tasks
Dim tsk As Task = Task.Run(Sub() ProcMyQ())
MyTasks.Add(tsk)
Next
End Sub
Private Sub ProcMyQ()
Do While Not MyBC.IsCompleted
Dim s As String = ""
Try
s = MyBC.Take 'block here
Catch ex As InvalidOperationException
' means that Take() was called on a completed collection
If MyBC.IsCompleted Then Exit Do
End Try
Debug.WriteLine(s)
Loop
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For x As Integer = 1 To 100
MyBC.Add(x.ToString)
Next
End Sub
End Class
-
Nov 4th, 2024, 01:27 PM
#7
Thread Starter
Frenzied Member
Re: Pulling from a queue using multiple tasks
Thanks, that seems to work. Just a quick question ... what's the reason for adding the tasks to a list?
-
Nov 4th, 2024, 01:39 PM
#8
Re: Pulling from a queue using multiple tasks
 Originally Posted by nbrege
Thanks, that seems to work. Just a quick question ... what's the reason for adding the tasks to a list?
Mostly habit. In case you need to know if all the tasks have completed. I should have shown that.
Code:
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
MyBC.CompleteAdding()
Task.WaitAll(MyTasks.ToArray)
End Sub
-
Nov 4th, 2024, 01:51 PM
#9
Thread Starter
Frenzied Member
Re: Pulling from a queue using multiple tasks
Thanks again. I think I can make this work for my particular application. I never knew there was such a thing as a BlockingCollection until today.
-
Nov 4th, 2024, 02:14 PM
#10
Thread Starter
Frenzied Member
Re: Pulling from a queue using multiple tasks
I have one more quick question ... is there a way to clear all the items from a BlockingCollection? I dont see a Clear method.
-
Nov 5th, 2024, 09:17 AM
#11
Re: Pulling from a queue using multiple tasks
 Originally Posted by nbrege
I have one more quick question ... is there a way to clear all the items from a BlockingCollection? I dont see a Clear method.
 Originally Posted by nbrege
Thanks again. I think I can make this work for my particular application. I never knew there was such a thing as a BlockingCollection until today.
I don't see a Clear either. Here is an approach.
Code:
While MyBC.TryTake(Nothing)
End While
I think if .CompleteAdding is set Takes and Adss will fail.
Last edited by dbasnett; Nov 5th, 2024 at 09:42 AM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|