Skip to content

Instantly share code, notes, and snippets.

@andrewstellman
Created September 4, 2021 15:40
Show Gist options
  • Save andrewstellman/592f2050f80931833c4a901b79bad7dc to your computer and use it in GitHub Desktop.
Save andrewstellman/592f2050f80931833c4a901b79bad7dc to your computer and use it in GitHub Desktop.
Weight randomized evergreen tweets by time since last sent in C#
using System;
using System.Linq;
namespace WeightByTime
{
record Tweet(long id, long time);
static class UnixTime
{
public static long EpochTime(this DateTime dateTime) =>
(long)dateTime.ToUniversalTime().Subtract(DateTime.UnixEpoch).TotalMilliseconds;
public static long EpochTime(this string date) =>
DateTime.Parse(date).EpochTime();
}
class Program
{
static readonly Random random = new();
static void Main(string[] args)
{
var tweets = new Tweet[]
{
new Tweet(1, "3 Feb 2021 07:21:32 GMT".EpochTime()),
new Tweet(2, "6 Feb 2021 12:31:46 GMT".EpochTime()),
new Tweet(3, "19 Feb 2021 17:16:46 GMT".EpochTime()),
new Tweet(4, "26 Feb 2021 06:14:26 GMT".EpochTime()),
new Tweet(5, "2 Mar 2021 02:53:12 GMT".EpochTime()),
new Tweet(6, "5 Mar 2021 17:27:34 GMT".EpochTime()),
new Tweet(7, "6 Mar 2021 15:19:37 GMT".EpochTime()),
new Tweet(8, "12 Mar 2021 18:22:37 GMT".EpochTime()),
new Tweet(9, "17 Mar 2021 03:01:15 GMT".EpochTime()),
new Tweet(10, "19 Mar 2021 14:12:13 GMT".EpochTime()),
};
for (int i = 0; i < 100; i++)
{
var weightedTweet = FindWeightedTweet(tweets);
Console.WriteLine("Found " + weightedTweet);
}
}
private static Tweet FindWeightedTweet(Tweet[] tweets)
{
var weights = tweets.Select(t => t.time);
var min = weights.Min();
var max = weights.Max() - min;
var weightedTweets = tweets.Select(t => new Tweet(t.id, (max - (t.time - min)) / 1000));
var totalWeights = weightedTweets.Select(t => t.time).Sum();
var randomWeight = random.Next((int)totalWeights);
var total = 0L;
foreach (var tweet in weightedTweets)
{
total += tweet.time;
if (total > randomWeight) return tweet;
}
return weightedTweets.Last();
}
}
}
@andrewstellman
Copy link
Author

andrewstellman commented Sep 5, 2021

According to the .NET System.Random documentation, if you don't ensure that the Random object is accessed in a thread-safe way, calls to methods that return random numbers return 0.

To make this threadsafe, replace line 19 with this:

        /// <summary>
        /// Static instance of random 
        /// </summary>
        /// <remarks>
        /// <see cref="https://docs.microsoft.com/en-us/dotnet/api/system.random?view=net-5.0#Multiple"/>
        /// </remarks>
        static readonly Random random = new();

        static object randomLocker = new object();

        /// <summary>
        /// Threadsafe call to random.Next
        /// </summary>
        /// <param name="max">Maximum value</param>
        /// <returns>Random number from 0 to max - 1</returns>
        static int Next(int max)
        {
            lock (randomLocker)
            {
                return random.Next(max);
            }
        }

and line 72 with this:

            var randomWeight = Next((int)totalWeights);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment