Don't use channels to send dependencies
This commit is contained in:
1 parent
8e507d76f3
commit
df39dd80b9
14 files changed
+223
-311
No files matched your search
+5
-47
@@ -11,18 +11,10 @@ use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::channel::oneshot;
|
||||
|
||||
use crate::error::DagError;
|
||||
use crate::task::Task;
|
||||
use crate::types::NodeId;
|
||||
|
||||
/// Type-erased channel endpoints (senders or receivers)
|
||||
type ErasedChannels = Vec<Box<dyn Any + Send>>;
|
||||
|
||||
/// Type-erased channel pair (senders, receivers)
|
||||
type ChannelPair = (ErasedChannels, ErasedChannels);
|
||||
|
||||
/// Type-erased async execution result (Arc-wrapped for efficient fanout)
|
||||
type ExecuteFuture =
|
||||
Pin<Box<dyn Future<Output = Result<Arc<dyn Any + Send + Sync>, DagError>> + Send>>;
|
||||
@@ -38,21 +30,13 @@ type ExecuteFuture =
|
||||
///
|
||||
/// This is an implementation detail and not part of the public API.
|
||||
pub(crate) trait ExecutableNode: Send {
|
||||
/// Create type-erased output channels for this node's dependents.
|
||||
///
|
||||
/// Returns (senders, receivers) where:
|
||||
/// - senders: Type-erased senders that this node will use to send outputs
|
||||
/// - receivers: Type-erased receivers that dependents will use to receive inputs
|
||||
fn create_output_channels(&self, num_dependents: usize) -> ChannelPair;
|
||||
|
||||
/// Execute the task with type-erased input receivers and output senders.
|
||||
///
|
||||
/// The TypedNode implementation knows the concrete types and can safely downcast.
|
||||
/// Consumes the node and returns the output value.
|
||||
fn execute_with_channels(
|
||||
fn execute_with_deps(
|
||||
self: Box<Self>,
|
||||
receivers: ErasedChannels,
|
||||
senders: ErasedChannels,
|
||||
dependencies: Vec<Arc<dyn Any + Send + Sync>>,
|
||||
) -> ExecuteFuture;
|
||||
}
|
||||
|
||||
@@ -86,30 +70,15 @@ where
|
||||
T::Input: 'static + Clone,
|
||||
T::Output: 'static + Clone,
|
||||
{
|
||||
fn create_output_channels(&self, num_dependents: usize) -> ChannelPair {
|
||||
let mut senders = Vec::new();
|
||||
let mut receivers = Vec::new();
|
||||
|
||||
for _ in 0..num_dependents {
|
||||
// Create channels that pass Arc-wrapped outputs (efficient for fanout)
|
||||
let (tx, rx) = oneshot::channel::<Arc<T::Output>>();
|
||||
senders.push(Box::new(tx) as Box<dyn Any + Send>);
|
||||
receivers.push(Box::new(rx) as Box<dyn Any + Send>);
|
||||
}
|
||||
|
||||
(senders, receivers)
|
||||
}
|
||||
|
||||
fn execute_with_channels(
|
||||
fn execute_with_deps(
|
||||
self: Box<Self>,
|
||||
receivers: ErasedChannels,
|
||||
senders: ErasedChannels,
|
||||
dependencies: Vec<Arc<dyn Any + Send + Sync>>,
|
||||
) -> ExecuteFuture {
|
||||
Box::pin(async move {
|
||||
// Use the task's extract_and_run method which has inline extraction logic
|
||||
// generated by the #[task] macro. This allows ANY type to work without
|
||||
// requiring ExtractInput trait implementations.
|
||||
let output = match self.task.extract_and_run(receivers).await {
|
||||
let output = match self.task.extract_and_run(dependencies).await {
|
||||
Ok(output) => output,
|
||||
Err(_msg) => {
|
||||
// Failed to extract input - likely channel closed or type mismatch
|
||||
@@ -124,17 +93,6 @@ where
|
||||
// Downstream tasks receive &T after extraction from Arc.
|
||||
let arc_output = Arc::new(output);
|
||||
|
||||
// Send Arc to all dependents via their channels
|
||||
// TypedNode<T> knows T::Output, so downcast is safe
|
||||
for sender_any in senders {
|
||||
if let Ok(sender) = sender_any.downcast::<oneshot::Sender<Arc<T::Output>>>() {
|
||||
// Clone Arc (just atomic refcount increment, NOT data clone)
|
||||
// This is the key performance optimization for fan-out patterns
|
||||
// Ignore send errors - dependent might have been cancelled
|
||||
let _ = sender.send(Arc::clone(&arc_output));
|
||||
}
|
||||
}
|
||||
|
||||
// Return Arc-wrapped output (for storage by runner)
|
||||
Ok(arc_output as Arc<dyn Any + Send + Sync>)
|
||||
})
|
||||
|
||||
Reference in new issue
Block a user