-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEtl.cs
More file actions
118 lines (100 loc) · 4.26 KB
/
Copy pathEtl.cs
File metadata and controls
118 lines (100 loc) · 4.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using static System.Threading.Tasks.Dataflow.DataflowBlockOptions;
namespace dataflow
{
public static class Etl
{
// [Producer] -> [Buffer] -> [Batch] -> [Action]
private const int ProducingRate = 50; //messages per sec
private const int BufferCapacity = Unbounded;
private const int BatchCapacity = Unbounded; //items, not batches!
private const bool BatchIsGreedy = true;
private const int ActionCapacity = Unbounded;
private const int ActionParallelism = 1;
private const int ActionRate = 2; //in batches, not items!
private const int BatchSize = 10;
private const int MaxItems = 999;
static readonly DataflowBlockOptions BufOpt = new DataflowBlockOptions
{
EnsureOrdered = false,
BoundedCapacity = BufferCapacity
};
static readonly GroupingDataflowBlockOptions BatchOpt = new GroupingDataflowBlockOptions
{
Greedy = BatchIsGreedy,
BoundedCapacity = BatchCapacity,
EnsureOrdered = false,
};
static readonly ExecutionDataflowBlockOptions ActionOpt = new ExecutionDataflowBlockOptions
{
BoundedCapacity = ActionCapacity,
MaxDegreeOfParallelism = ActionParallelism,
MaxMessagesPerTask = Unbounded,
SingleProducerConstrained = true,
EnsureOrdered = false
};
static Task ActionFn(int[] i)
{
Interlocked.Add(ref processed, i.Length);
Interlocked.Exchange(ref actIn, Action.InputCount);
return Task.Delay(1000 / ActionRate);
}
static readonly BufferBlock<int> Buffer = new BufferBlock<int>(BufOpt);
static readonly BatchBlock<int> Batch = new BatchBlock<int>(BatchSize, BatchOpt);
static readonly ActionBlock<int[]> Action =new ActionBlock<int[]>(ActionFn, ActionOpt);
static Etl()
{
Buffer.LinkTo(Batch);
Batch.LinkTo(Action);
}
internal static async Task Run()
{
StartMonitoring();
//produce items
foreach (var i in Enumerable.Range(1, MaxItems))
{
var result = await Buffer.SendAsync(i);
if(!result) throw new Exception("Failed to send " + i);
sent++;
await Task.Delay(1000 / ProducingRate);
}
await Task.Delay(TimeSpan.FromDays(1));
}
private static void StartMonitoring()
{
Task.Factory.StartNew(async () =>
{
while (true)
{
Render();
await Task.Delay(200); //rerender 5 fps
}
});
}
static int actIn = 0;
static int sent = 0;
static int processed = 0;
private static void Render()
{
var batchOut = Batch.OutputCount * BatchSize;
var actionIn = actIn * BatchSize;
var maxLen = Console.WindowWidth - 22; //text length
Console.Clear();
Console.WriteLine("sent: {0:000} " + ProgressBar(sent/(double)MaxItems, maxLen), sent);
Console.WriteLine("buf block len: {0:000} " + ProgressBar(Buffer.Count/(double)MaxItems, maxLen), Buffer.Count);
Console.WriteLine("batch out buf: {0:000} " + ProgressBar(batchOut/(double)MaxItems, maxLen), batchOut);
Console.WriteLine("act. in buf: {0:000} " + ProgressBar(actionIn/(double)MaxItems, maxLen), actionIn);
Console.WriteLine("processed: {0:000} " + ProgressBar(processed/(double)MaxItems, maxLen), processed);
}
static string ProgressBar(double progress, int maxWidth)
{
var len = maxWidth * progress;
var filled = (int) Math.Floor(len);
return string.Join("", Enumerable.Repeat("X", filled));
}
}
}