Threading
In a web application, ServerTextControl and MailMerge run on many threads at once: every request that creates a document runs on a thread of its own, and a batch job may start more. TX Text Control supports this, with one condition that decides how you write the code and how far it scales: shared resources are protected, so threads can wait for each other. Whether documents are created in request handlers, parallel loops or background services, the same rules decide how to create the instances, how far to parallelize and when to switch to processes.
How TX Text Control Handles Threads
TX Text Control is thread safe. It protects the resources that all instances in a process share with critical sections, parts of its code that only one thread runs at a time. When several threads need such a resource, they wait for each other. Text Control describes this as safe, but slower for specific applications.
For your application, this means:
- Threads work in parallel, but not without limit. Don't expect more threads in one process to make document processing proportionally faster: they meet at the critical sections.
- Large batches belong in processes. For merges of hundreds or thousands of documents, Text Control recommends several processes instead of several threads, as Multiple Processes describes.
- The members are synchronous.
Load,Saveand the merge methods ofMailMergehave no asynchronous versions. They occupy the calling thread until they return.
Create One Instance per Operation
Every piece of code that creates a document creates, initializes and disposes its own ServerTextControl inside the method that does the work, as Create and Dispose Instances describes. Nothing TX Text Control-related is shared between threads. A service class that a controller receives through dependency injection follows the same rule: it creates the instance in its method, not in its constructor, as the PdfService of Use ServerTextControl in Request Handlers does. A MailMerge works on the ServerTextControl of the same operation, connected through its TextComponent property. Instances that are never disposed make Create fail after some time on Windows, as Memory Usage explains.
Process Documents on Several Threads
The following console program converts all DOCX files of the folder Documents to PDF on up to four threads at the same time:
using TXTextControl;
string[] files = Directory.GetFiles("Documents", "*.docx");
Directory.CreateDirectory("Output");
ParallelOptions options = new ParallelOptions
{
// Find the best value with your own documents
MaxDegreeOfParallelism = 4
};
Parallel.ForEach(files, options, file =>
{
// Each operation works with an instance of its own
using (ServerTextControl tx = new ServerTextControl())
{
if (!tx.Create())
{
throw new InvalidOperationException("ServerTextControl could not be created.");
}
try
{
tx.Load(File.ReadAllBytes(file), BinaryStreamType.WordprocessingML);
tx.Save(out byte[] pdf, BinaryStreamType.AdobePDF);
string target = Path.Combine("Output", Path.GetFileNameWithoutExtension(file) + ".pdf");
File.WriteAllBytes(target, pdf);
}
catch (FilterException exception)
{
Console.WriteLine($"{Path.GetFileName(file)}: {exception.Reason}");
}
}
});
The code works as follows:
Parallel.ForEachruns the conversion for each file on a thread of the .NET thread pool.MaxDegreeOfParallelismlimits how many conversions run at the same time.- Each conversion creates, initializes and disposes its own
ServerTextControl. Nothing TX Text Control-related is shared between the threads. - Load reads the DOCX data, and Save writes the PDF document into a byte array in the BinaryStreamType
AdobePDF. - A FilterException reports a file that couldn't be loaded or saved, and the other files are converted anyway.
Text Control publishes no fixed number of threads or instances for a server. Measure with your own documents: increase MaxDegreeOfParallelism as long as the total time goes down, and keep the value at which it stops improving. In a web service, limit the documents that are created at the same time in the same way, as Keep the Service Responsive recommends.
Move Long Work Out of the Request
A request thread that creates a document of several seconds is blocked for that time. Accept such jobs, create the documents in a background service and notify the client when they're ready, as Keep the Service Responsive in REST Services describes. With many concurrent editors, run heavy processing in a separate application, as Container Scaling explains.
Set the Culture of Each Merge
MailMerge.MergeCulture formats numbers and dates in the merged document, and DataSourceCulture parses them in the data. Both default to the culture of the current thread. On a server, that's the culture of whichever thread runs the merge, which may not be the culture of your documents. Set both explicitly in each merge, as Parse Numbers and Dates With the Right Culture in Data Sources shows.
Next Steps
- Multiple Processes: merge large batches in parallel worker processes.
- Memory Usage: dispose instances and find those that are left behind.
- Performance Best Practices: the measures that make document processing faster.
- Creating Documents: the lifecycle of a
ServerTextControlinstance.