HigginsSoft.DotMpi
1.0.5-g64d87fa487
See the version list below for details.
dotnet add package HigginsSoft.DotMpi --version 1.0.5-g64d87fa487
NuGet\Install-Package HigginsSoft.DotMpi -Version 1.0.5-g64d87fa487
<PackageReference Include="HigginsSoft.DotMpi" Version="1.0.5-g64d87fa487" />
paket add HigginsSoft.DotMpi --version 1.0.5-g64d87fa487
#r "nuget: HigginsSoft.DotMpi, 1.0.5-g64d87fa487"
// Install HigginsSoft.DotMpi as a Cake Addin #addin nuget:?package=HigginsSoft.DotMpi&version=1.0.5-g64d87fa487&prerelease // Install HigginsSoft.DotMpi as a Cake Tool #tool nuget:?package=HigginsSoft.DotMpi&version=1.0.5-g64d87fa487&prerelease
DotMpi
DotMpi is a DotNet library that aims to bring multiprocessor functionality inspired by Open MPI to the DotNet world. It was developed as a solution to the limitations of DotNet's built-in Parallel.For
function, which often leads to a lack of performance due to thread starvation.
DotMpi enables control over which CPU processors to use, leading to increased performance. It was developed during the creation of a new C# math library for working with multiple precision integers, factoring numbers, and other number theory functions. The need for parallelization led to the development of DotMpi.
Using DotMpi, the library can now sieve numbers up to 2^31 in just half a second, which is nearly three times faster than wall time using bbuhrow's Yafu, which is implemented in c and uses highly tuned assembly. Yafu isn't likely using multiple cores for prime sieving, but it is still nice to see a DotNet implementation that runs faster.
DotMpi also opens up possibilities for proper stress testing, load testing, and concurrency testing in DotNet, as well as easily clustering workloads across network infrastructure.
Installation
To install DotMpi, simply clone the repository and add the project to your Visual Studio solution.
Usage
To use DotMpi, simply reference the DotMpi namespace in your code and use the available functions.
For convience, the syntax of the existing Parallel.For
is available as part of a fluent API.
var runner = Mpi
.ParallelFor(0, numThreads, target, i => new(i, "Hello World"))
.Run()
.Wait();
The Wait()
function will block until all processes have completed. If you do not want to block
instead of calling Wait()
just call Run()
and monitor execution with the methods available.
A current limitation is you can only call static
methods only as other processes will not have access to instance data
of the process launching the processor threads.
The Api requires the static method to be cast to a Func<>
to enforce strong typing of arguments in the method for serialization
of arguments and data between processes.
Additionally, arguments and returned data must be serializable as the libary uses IPC on named pipes, which requires binary serialization of data to pass information back and forth.
You can however pass any arguments need to the method that will be invoked and your method can return any state data you need.
Sample
Hello World
public static string MpiHelloWorld(int threadIndex, string message)
{
var p = Process.GetCurrentProcess();
int cpuNumber = 0;
for (var cpuMask = ((int)p.ProcessorAffinity); cpuMask > 1; cpuNumber++, cpuMask >>= 1) ;
return @$"{message} from thread {threadIndex} on process {p} on cpu {cpuNumber}";
}
public static void HelloWorldTest(int numThreads)
{
Func<int, string, string> target = MpiHelloWorld;
var timer = Stopwatch.StartNew();
var runner = Mpi
.ParallelFor(0, numThreads, target, i => new(i, "Hello World"))
.Run()
.Wait();
for (var i = 0; i < numThreads; i++)
{
var result = runner.Results[i];
Console.WriteLine($"[{DateTime.Now}] Result {i}: {result}");
}
Console.WriteLine($"[{DateTime.Now}] Completed {numThreads} process threads in {timer.Elapsed}");
timer.Stop();
}
Under the hood of the ParralelFor
fluent api call.
Mpi.Parallel(numThreads)
and Mpi.Parallel(start,end)
return a ParallelMethodBuilder
.
var builder = Mpi.Parallel(numThreads);
The builder can then be used to register a target function to execute.
var parallelMethod = builder.For(target);
Again, target needs to a Func<>
that points to a static method you wish to execute.
You can pass the arguments to parallelMethod either statically or using an argument provider delegate.
var parallelMethod = parallelMethod.WithArgs(arg0, arg1, arg2, ...);
These arguments need to match the type can count of the arguments in the target Func<>
For example. static string Method()
would be a Func<string>
and take no arguments, while static string Method(int a)
would be a
a Func<int, string>
In addition to providing static arguments, you can pass a delegate that will provide unique arguments to each process thread.
var parallelMethod = parallelMethod.WithArgs(i => new(arg1, arg2, arg3));
The argument provider delegate is definted as Func<int, ArgList<T0, ..., TN>
which will match the type parameters in your target method.
For convience the new constructor i => new(arg1, arg2, arg3)
provides simple way to define the function. You can also call another function
to provide arguments.
For exmaple:
public static HelloWorld(int threadIndex, string message)
=> $"Hello World from thread {threadIndex}";
public static string GetCustomArgs(int threadIndex)
=> threadIndex % 5 == 0 ? "Hello World" : "Good Bye World";
public static void HelloWorldTest(int numThreads)
{
Func<int, string, string> target = HelloWorld;
var runner = Mpi
.ParallelFor(0, numThreads, target, i => GetCustomArgs);
.Run()
.Wait();
for (var i = 0; i < numThreads; i++)
{
var result = runner.Results[i];
Console.WriteLine($"[{DateTime.Now}] Result {i}: {result}");
}
}
The unlike the target, the argument provider does not have to be static. For example, you can do:
public class CustomArgProvider
{
public string GetCustomArgs(int threadIndex)
=> threadIndex % 5 == 0 ? "Hello World" : "Good Bye World";
}
var provider = new CustomArgProvider();
Func<int, string, string> target = HelloWorld;
var runner = Mpi
.ParallelFor(0, numThreads, target, i => CustomArgProvider.GetCustomArgs);
.Run()
.Wait();
Roadmap
Detail the following:
-
- Introduction
- Brief overview of the project
- Introduction
-
- Motivation
- Discuss why DotMpi was created and the problem it solves
- Motivation
-
- Features
- List of features DotMpi provides
- Features
-
- Usage
- Quickstart guide to using DotMpi in your own project
- In-depth explanation of each feature and how to use it
- Usage
-
- Future plans
-
- Performance
- Discussion on the performance benefits of DotMpi
- Benchmarking data
- Performance
-
- Contributing
- Guidelines for contributing to DotMpi
- Contributing
-
- License
- Information about the project's license
- License
Checklist
- Introduction
- Title
- Brief overview of the project
- Motivation
- Explanation of why DotMpi was created and the problem it solves
- Features
- List of features DotMpi provides
- Usage
- Quickstart guide
- Installation
- Setting up a project
- Basic usage example
- In-depth explanation of each feature and how to use it
- Quickstart guide
- Future plans
- Authentication
- Remote connections
- Agent installe
- Custom serializers
- Event Api
- Code Cleanup / Refactoring
- Unit Tests
- Docs
- Wiki
- Nuget Package
- Performance
- Discussion on the performance benefits of DotMpi
- Benchmarking data
- Contributing
- Guidelines for contributing to DotMpi
- License
- Information about the project's license
Contributing
If you are interested in contributing to DotMpi, please submit a pull request with your changes and a description of the changes made.
License
DotMpi is licensed under the MIT License. See the LICENSE file for details.
Acknowledgments
Special thanks to the creators of Open MPI and bbuhrow's Yafu for inspiring and guiding the development of DotMpi.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- Newtonsoft.Json (>= 13.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.58 | 182 | 5/12/2023 |
1.0.57-beta.34211 | 64 | 5/12/2023 |
1.0.55-beta.1113 | 65 | 5/12/2023 |
1.0.54-beta.50615 | 65 | 5/12/2023 |
1.0.53-beta.47780 | 70 | 5/12/2023 |
1.0.52-beta.14220 | 63 | 5/12/2023 |
1.0.50 | 87 | 5/12/2023 |
1.0.50-beta.30352 | 63 | 5/12/2023 |
1.0.49 | 80 | 5/12/2023 |
1.0.49-beta.13306 | 63 | 5/12/2023 |
1.0.48-beta.6369 | 62 | 5/12/2023 |
1.0.47-beta.61754 | 61 | 5/12/2023 |
1.0.46-alpha.28014 | 61 | 5/12/2023 |
1.0.44-alpha.54729 | 60 | 5/12/2023 |
1.0.42 | 92 | 5/10/2023 |
1.0.41 | 81 | 5/10/2023 |
1.0.41-beta.499 | 62 | 5/10/2023 |
1.0.40-beta.18539 | 64 | 5/10/2023 |
1.0.39-beta.38369 | 58 | 5/10/2023 |
1.0.39-alpha.40147 | 68 | 5/10/2023 |
1.0.38-beta.39700 | 65 | 5/10/2023 |
1.0.38-alpha.39700 | 59 | 5/10/2023 |
1.0.36-alpha.58893 | 62 | 5/10/2023 |
1.0.34-alpha.17017 | 65 | 5/10/2023 |
1.0.22-alpha.53183 | 69 | 5/10/2023 |
1.0.21-alpha.17293 | 78 | 5/10/2023 |
1.0.20-alpha.4349 | 85 | 5/10/2023 |
1.0.19-alpha.55772 | 85 | 5/10/2023 |
1.0.13 | 157 | 5/9/2023 |
1.0.12 | 153 | 5/9/2023 |
1.0.11 | 174 | 5/8/2023 |
1.0.10 | 151 | 5/7/2023 |
1.0.9 | 168 | 5/7/2023 |
1.0.8 | 150 | 5/7/2023 |
1.0.7 | 153 | 5/7/2023 |
1.0.6 | 161 | 5/7/2023 |
1.0.5-g64d87fa487 | 122 | 5/7/2023 |
1.0.4-g2bfb41f6bc | 119 | 5/7/2023 |