0

I need an iteration of a parallel for loop to use 7 cores(or stay away from 1 core) but another iteration to use 8(all) cores and tried below code:

Parallel.For(0,2,i=>{
  if(i=0)
     Process.GetCurrentProcess().ProcessorAffinity = (System.IntPtr)(255);

  if(i==1)
     Process.GetCurrentProcess().ProcessorAffinity = (System.IntPtr)(254);
  Thread.Sleep(25);// to make sure  both set their affinities
  Console.WriteLine(Process.GetCurrentProcess().ProcessorAffinity);
});

this outputs 255 for both iterations. So either parallel.for loop is using single thread for them or one setting sets other iterations affinity too. Another problem is, this is from a latency sensitive application and all this affinity settings add 1 to 15 milliseconds latency.

Do I have to use threads explicitly and should I set affinities only once?

Edit: I tried threaded version, same thing happens. Even with explicit two threads, both writing 255 to console. Now it seems this command is for a process not a thread.

OpenCL context is using max cores for kernel execution on cpu in one iteration. Other iterations using 1-2 cores to copy buffers and send command to devices. When cpu is used by opencl, it uses all cores and devices cannot get enough time to copy buffers. Device fission seems to be harder than solving this issue I hink.

huseyin tugrul buyukisik
  • 11,469
  • 4
  • 45
  • 97
  • I don't know enough to help here, but does Parallel.For use threads or the task pool? Because I've seen it create and destroy degrees of parallelism based on the task pool demand. I'm pretty certain threads don't do that. I had maxDegree set at 26 operating 3.2Billion comparisons, and active threads would fluctuate between as low as 5 and 26 over the six days it took to complete. So while I can't help, I'm definitely interested in your question. – Shannon Holsinger Sep 16 '16 at 03:28
  • I couldn't find anything like minParallelismDegree for this but I'm trying pure threads using anonymous function delegate and event handler now. – huseyin tugrul buyukisik Sep 16 '16 at 03:31
  • It's an option you set in Parallel.For -- https://msdn.microsoft.com/en-us/library/system.threading.tasks.paralleloptions.maxdegreeofparallelism(v=vs.110).aspx as I said I'm ignorant but it might help you understand the under-the-hood stuff. – Shannon Holsinger Sep 16 '16 at 03:33
  • Notice that MSDN mentions "When the thread pool's heuristics is unable to determine the right number of threads to use and could end up injecting too many threads. For example, in long-running loop body iterations, the thread pool might not be able to tell the difference between reasonable progress or livelock or deadlock, and might not be able to reclaim threads that were added to improve performance. In this case, you can set the property to ensure that you don't use more than a reasonable number of threads" - so it does sound like "threads" are managed rather than assigned specifically. – Shannon Holsinger Sep 16 '16 at 03:35
  • @ShannonHolsinger just tried threads, same thing. Its about whole process I think. But MSDN says its for thread. "Sets the processors on which the associated thread can run." – huseyin tugrul buyukisik Sep 16 '16 at 03:54
  • I'm reading OS thread affinity now, which seems some more complicated. – huseyin tugrul buyukisik Sep 16 '16 at 04:01
  • 1
    Don't meddle with Threads from the pool. Your initial requirement, _... to use 7 cores(or stay away from 1 core)_ is highly suspect of being misinformed but when you really need this: forget about Parallel, Tasks and the pool. – H H Sep 16 '16 at 05:00
  • @HenkHolterman even in same thread, Stopwatch stopped working, Dictionary started duplicate .add and gave error. Maybe a thread isn't really a single thread anymore and I need locks around everything? I just need concurrent device control. Started with parallel, no problem. Maybe the anonymous function is causing this? I set it at a Func<> and used it as a delegate for 2 threads. – huseyin tugrul buyukisik Sep 16 '16 at 05:13
  • That sounds like a lot of related but different problems... Make sure you know the basics about threading and thread-safety. – H H Sep 16 '16 at 05:20
  • Is parallel.for seeming more safer than threads because in background it could be using only 1 thread (maybe main thread?) for just 2 iterations? – huseyin tugrul buyukisik Sep 16 '16 at 05:23
  • 1
    You quote MSDN but then use an entirely different property (on a Process) in your code. https://msdn.microsoft.com/en-us/library/system.diagnostics.process.processoraffinity(v=vs.110).aspx – Ian Mercer Sep 16 '16 at 05:47
  • @huseyintugrulbuyukisik - I think the key word there is "could be using only 1 thread" -- could be using more than one. This was all very interesting. Thanks toa all! – Shannon Holsinger Sep 16 '16 at 11:52

1 Answers1

2

Different thread affinities in Parallel.For Iterations

Question is misleading, as it is based on assumption that Parallel API means multiple threads. Parallel API does refer to Data Parallel processing, but doesn't provide any guarantee for invoking multiple threads, especially for the code provided above, where there's hardly any work per thread.

For the Parallel API, you can set the Max degree of Parallelism, as follows:

ParallelOptions parallelOption = new ParallelOptions();

parallelOption.MaxDegreeOfParallelism = Environment.ProcessorCount;

Parallel.For(0, 20, parallelOption, i =>

But that never guarantee the number of threads that would be invoked to parallel processing, since Threads are used from the ThreadPool and CLR decides at run-time, based on amount of work to be processed, whether more than one thread is required for the processing.

In the same Parallel loop can you try the following, print Thread.Current.ManageThreadId, this would provide a clear idea, regarding the number of threads being invoked in the Parallel loop.

Do I have to use threads explicitly and should I set affinities only once?

Edit: I tried threaded version, same thing happens. Even with explicit two threads, both writing 255 to console. Now it seems this command is for a process not a thread.

Can you post the code, for multiple threads, can you try something like this.

Thread[] threadArray = new Thread[2];
threadArray[0] = new Thread(<ThreadDelegate>);
threadArray[1] = new Thread(<ThreadDelegate>);
threadArray[0]. ProcessorAffinity = <Set Processor Affinity>
threadArray[1]. ProcessorAffinity = <Set Processor Affinity>

Assuming you assign the affinity correctly, you can print them and find different values, check the following ProcessThread.ProcessorAffinity.

On another note as you could see in the link above, you can set the value in hexadecimal based on processor affinity, not sure what does values 254, 255 denotes , do you really have server with that many processors.

EDIT:

Try the following edit to your program, (based on the fact that two Thread ids are getting printed), now by the time both threads some in the picture, they both get same value of variable i, they need a local variable to avoid closure issue

Parallel.For(0,2,i=>{
  int local = i;
  if(local=0)
     Process.GetCurrentProcess().ProcessorAffinity = (System.IntPtr)(255);

  if(local==1)
     Process.GetCurrentProcess().ProcessorAffinity = (System.IntPtr)(254);
  Thread.Sleep(25);// to make sure  both set their affinities
  Console.WriteLine(Process.GetCurrentProcess().ProcessorAffinity);
});

EDIT 2: (Would mostly not work as both threads might increment, before actual logic execution)

 int local = -1;
  Parallel.For(0,2,i=>{
  Interlocked.Increment(ref local);
  if(local=0)
     Process.GetCurrentProcess().ProcessorAffinity = (System.IntPtr)(255);

  if(local==1)
     Process.GetCurrentProcess().ProcessorAffinity = (System.IntPtr)(254);
  Thread.Sleep(25);// to make sure  both set their affinities
  Console.WriteLine(Process.GetCurrentProcess().ProcessorAffinity);
});
Community
  • 1
  • 1
Mrinal Kamboj
  • 11,300
  • 5
  • 40
  • 74
  • For the first part, it takes 20 to 200 milliseconds per iteration thats a load balancer and balances work to all devices and makes them equal latency. – huseyin tugrul buyukisik Sep 16 '16 at 05:24
  • --------------- Thread.Current.ManageThreadId 10 Thread.Current.ManageThreadId 16 --------------- its like this but only second one changes – huseyin tugrul buyukisik Sep 16 '16 at 05:28
  • Check the edit, if this is happening then mostly this is a closure issue, since by the time both threads come in the picture, `value of i is 0` for both of them – Mrinal Kamboj Sep 16 '16 at 05:33
  • I'm using i in a lock or using parallel.for's i and console writeline says 0 and 1 – huseyin tugrul buyukisik Sep 16 '16 at 05:34
  • 1
    `i in a lock` means, please provide code, this is a very common issue with multi thread variable values – Mrinal Kamboj Sep 16 '16 at 05:36
  • You may instead try `Interlocked.Increment` to a common variable, that would ensure that two threads will increment it once and you can test the logic – Mrinal Kamboj Sep 16 '16 at 05:38
  • Check the Edit 2 to achieve the same – Mrinal Kamboj Sep 16 '16 at 05:40
  • It was lock(obj){i++;} and initialized it with -1 so first iteration makes i = 0 and second iteration makes it i=1 – huseyin tugrul buyukisik Sep 16 '16 at 05:41
  • Ok this is also incorrect like my version of `Interlocked.Increment`, what happens is before you can reach the `if statement` both threads would have already been through the lock and still only one value exist, best solution is Edit 1, as that takes care of the closure issue in genuine sense. Though using `Interlocked.Increment` or `Lock` may provide the mixed results – Mrinal Kamboj Sep 16 '16 at 05:43
  • Also another point, regarding your code, you seems to be setting the `affinity for complete Process` not just `Thread` and `Process affinity` will impact all the Threads part of the process – Mrinal Kamboj Sep 16 '16 at 05:45
  • I changed to threadpool and used your local variable in that. It is jus as fast as parallel.for and now I'm sure there is no thread - based error. But pure threads are slower and that is bad since only pure thread version could be made OS thread and threadaffinity. – huseyin tugrul buyukisik Sep 16 '16 at 07:58
  • 1
    On a different note, please don't better with processor affinity, OS knows it best, your customization / prioritization may starve few threads. Also Closure is a very common issue in the Multi threaded applications – Mrinal Kamboj Sep 16 '16 at 09:06
  • That closure is weird as if it gets reference of i instead of value. – huseyin tugrul buyukisik Sep 16 '16 at 09:10