<p>I have a quad core machine and would like to write some code to parse a text file that takes advantage of all four cores. The text file basically contains one record per line.</p>

<p>Multithreading isn't my forte so I'm wondering if anyone could give me some patterns that I might be able to use to parse the file in an optimal manner.</p>

<p>My first thoughts are to read all the lines into some sort of queue and then spin up threads to pull the lines off the queue and process them, but that means the queue would have to exist in memory and these are fairly large files so I'm not so keen on that idea.</p>

<p>My next thoughts are to have some sort of controller that will read in a line and assign it a thread to parse, but I'm not sure if the controller will end up being a bottleneck if the threads are processing the lines faster than it can read and assign them.</p>

<p>I know there's probably another simpler solution than both of these but at the moment I'm just not seeing it.</p>

[{'answer_id': 7020, 'author': 'Mike Minutillo', 'author_id': 358, 'author_profile': 'https://Stackoverflow.com/users/358', 'pm_score': 4, 'selected': True, 'text': '<p>I\'d go with your original idea. If you are concerned that the queue might get too large implement a buffer-zone for it (i.e. If is gets above 100 lines the stop reading the file and if it gets below 20 then start reading again. You\'d need to do some testing to find the optimal barriers). Make it so that any of the threads can potentially be the "reader thread" as it has to lock the queue to pull an item out anyway it can also check to see if the "low buffer region" has been hit and start reading again. While it\'s doing this the other threads can read out the rest of the queue.</p>\n\n<p>Or if you prefer, have one reader thread assign the lines to three other <em>processor</em> threads (via their own queues) and implement a <a href="http://portal.acm.org/citation.cfm?doid=324133.324234" rel="noreferrer">work-stealing strategy</a>. I\'ve never done this so I don\'t know how hard it is.</p>\n'}, {'answer_id': 7023, 'author': 'C. K. Young', 'author_id': 13, 'author_profile': 'https://Stackoverflow.com/users/13', 'pm_score': 1, 'selected': False, 'text': '<p>My experience is with Java, not C#, so apologies if these solutions don\'t apply.</p>\n\n<p>The immediate solution I can think up off the top of my head would be to have an executor that runs 3 threads (using <a href="http://java.sun.com/javase/6/docs/api/java/util/concurrent/Executors.html" rel="nofollow noreferrer"><code>Executors</code></a><code>.newFixedThreadPool</code>, say). For each line/record read from the input file, fire off a job at the executor (using <a href="http://java.sun.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html" rel="nofollow noreferrer"><code>ExecutorService</code></a><code>.submit</code>). The executor will queue requests for you, and allocate between the 3 threads.</p>\n\n<p>Probably better solutions exist, but hopefully that will do the job. :-)</p>\n\n<p>ETA: Sounds a lot like Wolfbyte\'s second solution. :-)</p>\n\n<p>ETA2: <a href="http://msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx" rel="nofollow noreferrer"><code>System.Threading.ThreadPool</code></a> sounds like a very similar idea in .NET. I\'ve never used it, but it may be worth your while!</p>\n'}, {'answer_id': 7045, 'author': 'Mark Harrison', 'author_id': 116, 'author_profile': 'https://Stackoverflow.com/users/116', 'pm_score': 2, 'selected': False, 'text': '<p>This will eliminate bottlenecks of having a single thread do the reading:</p>\n\n<pre><code>open file\nfor each thread n=0,1,2,3:\n    seek to file offset 1/n*filesize\n    scan to next complete line\n    process all lines in your part of the file\n</code></pre>\n'}, {'answer_id': 7056, 'author': 'Derek Park', 'author_id': 872, 'author_profile': 'https://Stackoverflow.com/users/872', 'pm_score': 3, 'selected': False, 'text': "<p>Mark's answer is the simpler, more elegant solution.  Why build a complex program with inter-thread communication if it's not necessary?  Spawn 4 threads.  Each thread calculates size-of-file/4 to determine it's start point (and stop point).  Each thread can then work entirely independently.</p>\n\n<p>The <em>only</em> reason to add a special thread to handle reading is if you expect some lines to take a very long time to process <em>and</em> you expect that these lines are clustered in a single part of the file.  Adding inter-thread communication when you don't need it is a <em>very bad idea</em>.  You greatly increase the chance of introducing an unexpected bottleneck and/or synchronization bugs.</p>\n"}, {'answer_id': 7437, 'author': 'Derek Park', 'author_id': 872, 'author_profile': 'https://Stackoverflow.com/users/872', 'pm_score': 0, 'selected': False, 'text': '<p>@lomaxx</p>\n\n<blockquote>\n  <p>@Derek &amp; Mark: I wish there was a way to accept 2 answers. I\'m going to have to end up going with Wolfbyte\'s solution because if I split the file into n sections there is the potential for a thread to come across a batch of "slow" transactions, however if I was processing a file where each process was guaranteed to require an equal amount of processing then I really like your solution of just splitting the file into chunks and assigning each chunk to a thread and being done with it.</p>\n</blockquote>\n\n<p>No worries.  If clustered "slow" transactions is a issue, then the queuing solution is the way to go.  Depending on how fast or slow the average transaction is, you might also want to look at assigning multiple lines at a time to each worker.  This will cut down on synchronization overhead.  Likewise, you might need to optimize your buffer size.  Of course, both of these are optimizations that you should probably only do after profiling.  (No point in worrying about synchronization if it\'s not a bottleneck.)</p>\n'}, {'answer_id': 7529, 'author': 'graham.reeds', 'author_id': 342, 'author_profile': 'https://Stackoverflow.com/users/342', 'pm_score': 1, 'selected': False, 'text': '<p>Since the bottleneck will generally be in the processing and not the reading when dealing with files I\'d go with the <a href="http://www.ddj.com/architect/184401751" rel="nofollow noreferrer">producer-consumer</a> pattern. To avoid locking I\'d look at lock free lists. Since you are using C# you can take a look at Julian Bucknall\'s <a href="http://www.boyet.com/Articles/LockfreeFreeList.html" rel="nofollow noreferrer">Lock-Free List</a> code.</p>\n'}, {'answer_id': 79983, 'author': 'Adisak', 'author_id': 14904, 'author_profile': 'https://Stackoverflow.com/users/14904', 'pm_score': 0, 'selected': False, 'text': '<p>If the text that you are parsing is made up of repeated strings and tokens, break the file into chunks and for each chunk you could have one thread pre-parse it into tokens consisting of keywords, "punctuation", ID strings, and values.  String compares and lookups can be quite expensive and passing this off to several worker threads can speed up the purely logical / semantic part of the code if it doesn\'t have to do the string lookups and comparisons.</p>\n\n<p>The pre-parsed data chunks (where you have already done all the string comparisons and "tokenized" it) can then be passed to the part of the code that would actually look at the semantics and ordering of the tokenized data.</p>\n\n<p>Also, you mention you are concerned with the size of your file occupying a large amount of memory.  There are a couple things you could do to cut back on your memory budget.</p>\n\n<p>Split the file into chunks and parse it.  Read in only as many chunks as you are working on at a time plus a few for "read ahead" so you do not stall on disk when you finish processing a chunk before you go to the next chunk.</p>\n\n<p>Alternatively, large files can be memory mapped and "demand" loaded.  If you have more threads working on processing the file than CPUs (usually threads = 1.5-2X CPU\'s is a good number for demand paging apps), the threads that are stalling on IO for the memory mapped file will halt automatically from the OS until their memory is ready and the other threads will continue to process.</p>\n'}]
['https://Stackoverflow.com/questions/7015', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/493/']