template<typename T>
class ROOT::Experimental::TDF::TResultProxy< T >
Smart pointer for the return type of actions.
A wrapper around the result of TDataFrame actions able to trigger calculations lazily.
- Template Parameters
-
T | Type of the action result |
A smart pointer which allows to access the result of a TDataFrame action. The methods of the encapsulated object can be accessed via the arrow operator. Upon invocation of the arrow operator or dereferencing (operator*
), the loop on the events and calculations of all scheduled actions are executed if needed. It is possible to iterate on the result proxy if the proxied object is a collection.
for (auto& myItem : myResultProxy) { ... };
If iteration is not supported by the type of the proxied object, a compilation error is thrown.
Definition at line 27 of file TResultProxy.hxx.
Register a callback that TDataFrame will execute "everyNEvents" on a partial result.
- Parameters
-
[in] | everyNEvents | Frequency at which the callback will be called, as a number of events processed |
[in] | callback | a callable with signature void(Value_t&) where Value_t is the type of the value contained in this TResultProxy |
- Returns
- this TResultProxy, to allow chaining of OnPartialResultSlot with other calls
The callback must be a callable (lambda, function, functor class...) that takes a reference to the result type as argument and returns nothing. TDataFrame will invoke registered callbacks passing partial action results as arguments to them (e.g. a histogram filled with a part of the selected events, a counter incremented only up to a certain point, a mean over a subset of the events and so forth).
Callbacks can be used e.g. to inspect partial results of the analysis while the event loop is running. For example one can draw an up-to-date version of a result histogram every 100 entries like this:
auto h = tdf.Histo1D("x");
h.OnPartialResult(100, [&c](
TH1D &h_) { c.cd(); h_.
Draw(); c.Update(); });
h->Draw();
A value of 0 for everyNEvents indicates the callback must be executed only once, before running the event loop. A conveniece definition kOnce
is provided to make this fact more expressive in user code (see snippet below). Multiple callbacks can be registered with the same TResultProxy (i.e. results of TDataFrame actions) and will be executed sequentially. Callbacks are executed in the order they were registered. The type of the value contained in a TResultProxy is also available as TResultProxy<T>::Value_t, e.g.
auto h = tdf.Histo1D("x");
When implicit multi-threading is enabled, the callback:
- will never be executed by multiple threads concurrently: it needs not be thread-safe. For example the snippet above that draws the partial histogram on a canvas works seamlessly in multi-thread event loops.
- will always be executed "everyNEvents": partial results will "contain" that number of events more from one call to the next
- might be executed by a different worker thread at different times: the value of
std::this_thread::get_id()
might change between calls To register a callback that is called by each worker thread (concurrently) every N events one can use OnPartialResultSlot.
Definition at line 215 of file TResultProxy.hxx.
Register a callback that TDataFrame will execute in each worker thread concurrently on that thread's partial result.
- Parameters
-
[in] | everyNEvents | Frequency at which the callback will be called by each thread, as a number of events processed |
[in] | a | callable with signature void(unsigned int, Value_t&) where Value_t is the type of the value contained in this TResultProxy |
- Returns
- this TResultProxy, to allow chaining of OnPartialResultSlot with other calls
See OnPartialResult
for a generic explanation of the callback mechanism. Compared to OnPartialResult
, this method has two major differences:
- all worker threads invoke the callback once every specified number of events. The event count is per-thread, and callback invocation might happen concurrently (i.e. the callback must be thread-safe)
- the callable must take an extra
unsigned int
parameter corresponding to a multi-thread "processing slot": this is a "helper value" to simplify writing thread-safe callbacks: different worker threads might invoke the callback concurrently but always with different slot
numbers.
- a value of 0 for everyNEvents indicates the callback must be executed once per slot.
For example, the following snippet prints out a thread-safe progress bar of the events processed by TDataFrame
auto c = tdf.Count();
std::string progress;
std::mutex bar_mutex;
c.OnPartialResultSlot(nEvents / 100, [&progress, &bar_mutex](unsigned int, ULong64_t &) {
std::lock_guard<std::mutex> lg(bar_mutex);
progress.push_back('#');
std::cout << "\r[" << std::left << std::setw(100) << progress << ']' << std::flush;
});
std::cout << "Analysis running..." << std::endl;
*c;
std::cout << "\nDone!" << std::endl;
Definition at line 261 of file TResultProxy.hxx.