Adapted from the ntpl007_mtFill tutorial.
#include <atomic>
#include <memory>
#include <mutex>
#include <thread>
#include <vector>
#include <utility>
constexpr char const *kNTupleFileName = "ntpl009_parallelWriter.root";
constexpr int kNWriterThreads = 4;
constexpr int kNEventsPerThread = 25000;
void FillData(RNTupleParallelWriter *
writer)
{
static std::atomic<std::uint32_t> gThreadId;
const auto threadId = ++gThreadId;
auto prng = std::make_unique<TRandom3>();
prng->SetSeed();
auto fillContext =
writer->CreateFillContext();
auto entry = fillContext->CreateEntry();
auto id = entry->GetPtr<std::uint32_t>("id");
*id = threadId;
auto vpx = entry->GetPtr<std::vector<float>>("vpx");
auto vpy = entry->GetPtr<std::vector<float>>("vpy");
auto vpz = entry->GetPtr<std::vector<float>>("vpz");
for (int i = 0; i < kNEventsPerThread; i++) {
vpx->clear();
vpy->clear();
vpz->clear();
int npx = static_cast<int>(prng->Rndm(1) * 15);
for (int j = 0; j < npx; ++j) {
float px, py, pz;
prng->Rannor(px, py);
pz = px * px + py * py;
vpx->emplace_back(px);
vpy->emplace_back(py);
vpz->emplace_back(pz);
}
fillContext->Fill(*entry);
}
}
void Write()
{
auto model = RNTupleModel::CreateBare();
model->MakeField<std::uint32_t>("id");
model->MakeField<std::vector<float>>("vpx");
model->MakeField<std::vector<float>>("vpy");
model->MakeField<std::vector<float>>("vpz");
RNTupleWriteOptions options;
options.SetApproxZippedClusterSize(1024 * 1024);
auto writer = RNTupleParallelWriter::Recreate(std::move(model),
"NTuple", kNTupleFileName, options);
std::vector<std::thread> threads;
for (int i = 0; i < kNWriterThreads; ++i)
threads.emplace_back(FillData,
writer.get());
for (int i = 0; i < kNWriterThreads; ++i)
threads[i].join();
}
void Read()
{
auto reader = RNTupleReader::Open("NTuple", kNTupleFileName);
auto viewVpx = reader->GetView<float>("vpx._0");
TCanvas *
c1 =
new TCanvas(
"c2",
"Multi-Threaded Filling Example", 200, 10, 1500, 500);
TH1F h(
"h",
"This is the px distribution", 100, -4, 4);
auto nEvents = reader->GetNEntries();
auto viewId = reader->GetView<std::uint32_t>("id");
TH2F hFillSequence(
"",
"Entry Id vs Thread Id;Entry Sequence Number;Filling Thread", 100, 0, nEvents, 100, 0,
kNWriterThreads + 1);
for (auto i : reader->GetEntryRange())
hFillSequence.Fill(i, viewId(i));
hFillSequence.DrawCopy();
}
void ntpl009_parallelWriter()
{
Write();
Read();
}
R__EXTERN TStyle * gStyle
The RNTupleModel encapulates the schema of an ntuple.
A writer to fill an RNTuple from multiple contexts.
An RNTuple that is used to read data from storage.
Common user-tunable settings for storing ntuples.
1-D histogram with a float per channel (see TH1 documentation)
2-D histogram with a float per channel (see TH1 documentation)
void SetOptStat(Int_t stat=1)
The type of information printed in the histogram statistics box can be selected via the parameter mod...
RNTupleGlobalRange GetFieldRange(const RFieldBase &field, const RPageSource &pageSource)
Helper to get the iteration space of the given field that needs to be connected to the given page sou...