Click here to Skip to main content
15,938,218 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
i have a for loop calling a function that draw some shapes and save it as png and it is using only one core of my cpu ~25%, how i can make it use the full cores or cpu, i'm using vb.net & wpf,and i searched through the internet for anything near that i couldn't find,so any tips will help.

new EDIT from hear:

ok i'm going to ask this again (in case my question was not clear above):
i got this loop:
VB
For i = 1 To lastframe
   TextOverImg()
Next

and it call this function:
VB
function TextOverImg()
    Dim txtRec As Rect = New Rect(0, 0, 1000, 1000)
    'environment creating for drawing
    Dim dvText As New DrawingVisual()
    Dim dcText As DrawingContext = dvText.RenderOpen()
    'changing texture width to single lines width
    txtRec = New Rect(0, 0, fText.MaxTextWidth, fText.Height)
    dcText.DrawRectangle(Brushes.WhiteSmoke, New Pen(Brushes.Black, 10.0), txtRec)
    dcText.DrawText(fText, New Point(txtRec.X, txtRec.Y))
    dcText.Close()
    'bitmap from text
    Dim textPlate As New RenderTargetBitmap(txtRec.Width, txtRec.Height, 96, 96, PixelFormats.Pbgra32)
    textPlate.Render(dvText)
    'path to save
    Dim path As String = imgSave
    Dim fs As FileStream = New FileStream(path, FileMode.Create)
    'encoding to PNG and saving
    Dim encoder As BitmapEncoder = New PngBitmapEncoder()
    encoder.Frames.Add(BitmapFrame.Create(imgResize))
    encoder.Save(fs)
end function

now when i launch the loop it uses only a 25% from my CPU, now what i want is to run 4 loops instead of this one loop but simultaneously, and then it will get me finish earlier in about 1/4 the 1 loop time, the priority is for time no other function will run @ the same time or be any UI manipulation or reporting, think of it as forward rendering app, it takes some inputs and launches the loop.

now i found about the background worker, if i launched 4 loops in a 4 background workers, will they run simultaneously ???
if any one got a better solution please I'm listening :)

PS: i don't care now about extremely bad quality of the code (at least for now) as i'm very tight with the time, after a while i'll be going back and refactor the code.
Posted
Updated 3-Jul-11 12:47pm
v3

Your goal is not loading about 100% of the core but improving throughput of application and responsiveness of the system. Actually, using 100% of the core by some UI application is more typically a sign of abuse of programming technique and extremely bad quality of the code.

If you don't input anything and your UI is not loaded with something serious in the background, correct UI should use exactly zero CPU time.

Multithreading is indeed a key to any non-trivial UI application. Please look at my collection of links to my past answers:
How to get a keydown event to operate on a different thread in vb.net[^],
Control events not firing after enable disable + multithreading[^].

If you need to know something specific, please ask your follow-up questions.

[EDIT — answering a question after the code is posted]

Well, the ultimate goal of all this activity is not know to me so far.
I suspect you don't need DrawingVisual. What do you do, just draw on some bitmap? If you draw on the context of DrawingVisual you won't be able to call the methods in a non-UI thread; instead, you will have to dispatch the calls to UI thread using Dispatcher. And the UI thread will dispatch the changes in the rendering threads. In this way, your WPF threads make a bottleneck no matter how fast your separate threads work. The threads will run in parallel, but it will be some mixture of thread scheduling/switching and actual execution of different cores. If you want to have more thread then cores, you won't improve parallelism at all but will load CPU more due the thread synchronization overhead. Again, what's the ultimate purpose of this activity?

The problem of throughput will need some research anyway.

—SA
 
Share this answer
 
v3
Comments
bat3a 3-Jul-11 11:11am    
thanks man, but it is a non-trivial UI application, actually there are no UI it is a hidden app, and it has a dedicated workstation for it,i executed my app 4 times simultaneously, each one deals with a part of the loop, the result is as desired and done in about 1/4 the time, my problem lies in management and communication between the app 4 instances.

so i'm looking for a multi-threading solution,which from 1 instance of the app i can fire 4 processes simultaneously to do the same job without splitting the job on 4 instances, and i can't find a guide, so if you have any good references i'd be thankful.
Sergey Alexandrovich Kryukov 3-Jul-11 16:34pm    
Why "but"? This is what I say: most non-trivial applications nee multithreading. As you don't really describe any problems, you got just a bunch of general ideas and technique from my answer. About communication between thread, please read my article on blocking queue (referenced in first link).
--SA
bat3a 3-Jul-11 18:48pm    
i updated the question above.
bat3a 3-Jul-11 22:28pm    
sorry i saw your edit after i submitted my solution.
the main function of the app is reading text from a file and rendering it to an image, added to a viewport3d geometry material brush, transforming the geometry then rendering the viewport3d visual to an image and saving it as png.
You can use the BackgroundWorker[^] class to start threads. One thing that occurs to me, how many cores does your processor have ? If you have 4 cores, then that's one reason you're using 25%, you're maxing out your one core. I have 8 cores. Some people have 2. In other words, I wonder if the number of threads you want to start for the fastest result, will depend on the machine. Ideally, I'd suggest you start X-1, where x is the number of cores, so that your UI remains responsive. If your UI is not responsive, Windows 7 can decide to shut down your program, even if it's working fine.
 
Share this answer
 
Comments
bat3a 3-Jul-11 22:04pm    
answering your questions:
i thought about that before and although i have 4 cores but it seems that it uses them all @6% each which totals ~ 25% of all.
and i already use the background worker, but i don't know how start more than one thread simultaneously, i think a key to the answer is in my solution down...
through searching the internet more and more, i found the Task Class which you can feed him a collection of functions and executing them simultaneously, and i'm able to test that correctly using this code: just add a button and a textbox
VB
Imports System.Threading.Tasks
Class MainWindow
    Sub test0()
        'simulating some process
        System.Threading.Thread.Sleep(1000)
    End Sub
    Sub test1()
        'simulating some process
        System.Threading.Thread.Sleep(1000)
    End Sub
    Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
        'you can even try duplicating the same function
        Dim taskA = New Task(Sub() test0(), Sub() test1())
        ' Start the task
        taskA.Start()
        'waiting for the task to complete, if you checked the status in less than 1000 it will be running still
        'but if you checked the status alittle more than 1000 say 1010 it will be completed (for the two functions)
        System.Threading.Thread.Sleep(1010)
        TextBox1.Text += taskA.Status.ToString
    End Sub

End Class


but i'm still integrating that in my code, i'll report here if i found a problem.
 
Share this answer
 
Comments
Christian Graus 3-Jul-11 22:27pm    
Calling 'sleep' is obviously the opposite of what you want. There's no reason you can't add many background workers, AFAIK.
bat3a 3-Jul-11 22:35pm    
i'm calling "sleep" just to emulate doing some work no more, do you have a code snippet i could learn from.
bat3a 4-Jul-11 17:04pm    
i added down another stage of the problem!!
Sergey Alexandrovich Kryukov 5-Jul-11 0:16am    
You should understand that tasks work on top of threads. This is a tool for abstracting threads to improve parallelism. If the threads are logically independent tasks with distinctly different functions, explicit thread should be used.
--SA
no after trying to integrate that in my code, i get this exception:

System.InvalidOperationException was unhandled by user code<br />
  Message=The calling thread must be STA, because many UI components require this.<br />
  Source=PresentationCore<br />
  StackTrace:<br />
       at System.Windows.Input.InputManager..ctor()<br />
       at System.Windows.Input.InputManager.GetCurrentInputManagerImpl()<br />
       at System.Windows.Input.KeyboardNavigation..ctor()<br />
       at System.Windows.FrameworkElement.FrameworkServices..ctor()<br />
       at System.Windows.FrameworkElement.EnsureFrameworkServices()<br />
       at System.Windows.FrameworkElement..ctor()<br />
       at System.Windows.Controls.Viewport3D..ctor()<br />
       at WpfApplication1.MainWindow.TextOverImg(ImageSource imagePlate, String imgSave, Double trans, FormattedText fText, FormattedText sText, String[] imgCoords, Int32 Lines) in C:\Users\CRAX\Documents\Visual Studio 2010\Projects\task test\MainWindow.xaml.vb:line 59<br />
       at WpfApplication1.MainWindow._Closure$__1._Lambda$__1() in C:\Users\CRAX\Documents\Visual Studio 2010\Projects\task test\MainWindow.xaml.vb:line 313<br />
       at System.Threading.Tasks.Task.InnerInvoke()<br />
       at System.Threading.Tasks.Task.Execute()<br />
  InnerException: 



here is my code, it includes two functions and button.click event for calling the parallel:
VB
Public Function TextOverImg(imagePlate As ImageSource, ByVal imgSave As String,
           ByVal trans As Double, ByVal fText As FormattedText, ByVal sText As FormattedText,
	     ByVal imgCoords() As String, ByVal Lines As Integer)
 
    'whole drawing area
    Dim rec As Rect = New Rect(0, 0, 720, 576)
 
    'text drawing size
    Dim txtRec As Rect = New Rect(0, 0, 1000, 1000)
 
    Dim dvText As New DrawingVisual()
    Dim dcText As DrawingContext = dvText.RenderOpen()

    'scale bitmap for better antialiasing
    Dim sc As Integer = 300 / 96
 
      'changing texture width to single lines width
      txtRec = New Rect(0, 0, fText.MaxTextWidth, fText.Height)
 
      fText.TextAlignment = TextAlignment.Center
      sText.TextAlignment = TextAlignment.Center
 
      'reading text transperancy
      Dim trns As String = 100
 
      dcText.DrawRectangle(Brushes.WhiteSmoke, New Pen(Brushes.Black, 10.0), txtRec)
      dcText.DrawText(sText, New Point(txtRec.X + 3, txtRec.Y + 3))
      dcText.DrawText(fText, New Point(txtRec.X, txtRec.Y))
    dcText.Close()
 
    'bitmap from text
    Dim textPlate As New RenderTargetBitmap(720, 576, 96, 96, PixelFormats.Pbgra32)
    textPlate.Render(dvText)
 
      'loading coords and transforming textplate accordingly 
      If Not (trans = 0) Then
 
        'definning the viewport
        Dim viewport3d As New Viewport3D
        viewport3d.Width = rec.Width
        viewport3d.Height = rec.Height
        viewport3d.Measure(New Size(rec.Width, rec.Height))
        viewport3d.Arrange(rec)
 
        'define camera
        Dim cam As New OrthographicCamera
        cam.Position = New Point3D(0.5, 0.5, 1)
        viewport3d.Camera = cam
 
        Dim mv3d As New ModelVisual3D
        Dim mgrp3d As New Model3DGroup
        Dim gm3d As New GeometryModel3D
 
        'define light
        Dim light As New AmbientLight
        light.Color = Colors.White
        mgrp3d.Children.Add(light)
 
        'define mesh object
        Dim mesh3d As New MeshGeometry3D()
        Dim meshpoints As New Point3DCollection
        mesh3d.Positions.Add(New Point3D(0, 0, 0))
        mesh3d.Positions.Add(New Point3D(0, 1, 0))
        mesh3d.Positions.Add(New Point3D(1, 0, 0))
        mesh3d.Positions.Add(New Point3D(1, 1, 0))
 
        mesh3d.TextureCoordinates.Add(New Point(0, 1))
        mesh3d.TextureCoordinates.Add(New Point(0, 0))
        mesh3d.TextureCoordinates.Add(New Point(1, 1))
        mesh3d.TextureCoordinates.Add(New Point(1, 0))
 
        mesh3d.TriangleIndices.Add(0)
        mesh3d.TriangleIndices.Add(2)
        mesh3d.TriangleIndices.Add(1)
        mesh3d.TriangleIndices.Add(2)
        mesh3d.TriangleIndices.Add(3)
        mesh3d.TriangleIndices.Add(1)
 
        ' Apply the mesh to the geometry model.
        gm3d.Geometry = mesh3d
 
        ' Define material and apply to the mesh geometries.
        Dim mat As New DiffuseMaterial
        mat.Brush = New ImageBrush(textPlate)
        gm3d.Material = mat
 
        'new context for merging image under transformed text
        Dim dvMerge As New DrawingVisual()
        Dim dcMerge As DrawingContext = dvMerge.RenderOpen()
 
        'adding imgPlate 1st
        dcMerge.DrawImage(imagePlate, rec)
 
        Dim imgC() As String = imgCoords(0).Split("&")
        Dim imgCoordsln() As String = imgC(2).Split(Environment.NewLine)
 
        Dim pointsTransformed As Point3D() = New Point3D(3) {}
        'setting the points to array
        For i = 1 To 4 Step 1
          Dim points() As String
          points = imgCoordsln(i).Split(",")
          pointsTransformed(i - 1) = New Point3D(Val(points(0)), Val(points(1)), Val(points(2)))
        Next
        Dim xfrm As New MatrixTransform3D
 
        'transforming the geometry
        xfrm.Matrix = CalculateNonAffineTransform(pointsTransformed)
        gm3d.Transform = xfrm
        mgrp3d.Children.Add(gm3d)
        mv3d.Content = mgrp3d
        viewport3d.Children.Add(mv3d)
        
	dcMerge.Close()
 
        'rendering viewport3D to image
        Dim Mergedbmp As New RenderTargetBitmap(720 * sc, 576 * sc, 96 * sc, 96 * sc, PixelFormats.Pbgra32)
        Mergedbmp.Render(dvMerge)
        Mergedbmp.Render(viewport3d)
 
        'resizing to custom size
        Dim imgResize As New TransformedBitmap()
        imgResize.BeginInit()
        imgResize.Source = Mergedbmp
        imgResize.Transform = New ScaleTransform(0.3335, 0.3335)
        imgResize.EndInit()
 
        'path to save
        Dim path As String = imgSave
        Dim fs As FileStream = New FileStream(path, FileMode.Create)
 
        'encoding to PNG and saving
        Dim encoder As BitmapEncoder = New PngBitmapEncoder()
        encoder.Frames.Add(BitmapFrame.Create(imgResize))
        encoder.Save(fs)
 
        'preview exported image
        Return Mergedbmp
    End If
    Return imagePlate
  End Function

does any one know why this happens???
 
Share this answer
 
v3
You said:

i don't care now about extremely bad quality of the code (at least for now) as i'm very tight with the time, after a while i'll be going back and refactor the code.

You must be a fairly inexperienced programmer. I've been doing this for thirty years, and have NEVER had time to go back and refactor code.

It looks to me like your code needs refactoring RIGHT NOW.

If your code is using 25% of the CPU, you should count your blessings. Using 100% of the CPU is not only bad practice, but is generally frowned upon by pretty much every programmer I know. .Net will use as much of the CPU as it needs to, and will automatically utilize as much of the system's resources as it needs to (including core utilization and thread affinity). If your code was running without any exceptions in its original configuration, my advice is to put it back the way it was.
 
Share this answer
 
Comments
bat3a 4-Jul-11 17:54pm    
well thanks for the help!!!
but if you consider yourself a pro-programmer then at least you could point what is wrong it the code instead of judging it, i'm looking for help NOT critiques.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900