示例#1
0
        public void TestDSLocalInMemoryLogger()
        {
            // Logger for manually completed events
            var logger1 = new InMemoryLogger <FoodContext, int>(TimeSpan.MaxValue);
            // Logger that completes events automatically after 10ms (experimental unit duration)
            var logger2 = new InMemoryLogger <FoodContext, int>(new TimeSpan(0, 0, 0, 0, 10));
            var context = new FoodContext {
                Actions = new int[] { 1, 2, 3 }, UserLocation = "HealthyTown"
            };
            string guid1 = Guid.NewGuid().ToString();
            string guid2 = Guid.NewGuid().ToString();

            // Ensure manually completed events appear
            logger1.Record(context, 1, null, null, guid1);
            logger1.Record(context, 2, null, null, guid2);
            logger1.ReportRewardAndComplete(guid1, (float)2.0);
            logger1.ReportRewardAndComplete(guid2, (float)2.0);
            var dps1 = logger1.FlushCompleteEvents();

            Assert.IsTrue(dps1.Length == 2);
            string[] guids = { dps1[0].Key, dps1[1].Key };
            Assert.IsTrue(guids.Contains(guid1) && guids.Contains(guid2));

            // Ensure experimental unit duration works
            logger2.Record(context, 1, null, null, guid1);
            // The tick resolution in Windows is typically 15ms, so give some allowance
            Thread.Sleep(20);
            var dps2 = logger2.FlushCompleteEvents();

            Assert.IsTrue(dps2.Length == 1);
            // Since no reward was reported, the reward should be the default value
            Assert.IsTrue((dps2[0].Key == guid1) && (dps2[0].Reward == 0.0));

            // Use experimental unit and manually completed events simultaneously
            logger2.Record(context, 1, null, null, guid1);
            logger2.Record(context, 2, null, null, guid2);
            logger2.ReportRewardAndComplete(guid1, (float)2.0);
            dps2 = logger2.FlushCompleteEvents();
            Assert.IsTrue((dps2.Length == 1) && (dps2[0].Key == guid1));
            Thread.Sleep(50);
            dps2 = logger2.FlushCompleteEvents();
            Assert.IsTrue((dps2.Length == 1) && (dps2[0].Key == guid2));

            // Ensure multithreaded inserts yield correct results
            const int     NumThreads         = 16;
            const int     NumEventsPerThread = 100;
            List <Thread> threads            = new List <Thread>(NumThreads);

            for (int i = 0; i < NumThreads; i++)
            {
                threads.Add(new Thread(() =>
                {
                    for (int j = 0; j < NumEventsPerThread; j++)
                    {
                        string guid = Guid.NewGuid().ToString();
                        // Test manual logger
                        logger1.Record(context, 1, null, null, guid);
                        logger1.ReportRewardAndComplete(guid, (float)3.0);
                        // Test experimental unit logger
                        logger2.Record(context, 1, null, null, guid);
                        logger2.ReportReward(guid, (float)4.0);
                    }
                }));
            }
            foreach (Thread t in threads)
            {
                t.Start();
            }
            foreach (Thread t in threads)
            {
                t.Join();
            }
            dps1 = logger1.FlushCompleteEvents();
            Assert.IsTrue(dps1.Length == NumThreads * NumEventsPerThread);
            Thread.Sleep(50);
            dps2 = logger2.FlushCompleteEvents();
            Assert.IsTrue(dps2.Length == NumThreads * NumEventsPerThread);
            // Ensure the reward information was recorded before the event expired
            foreach (var dp in dps2)
            {
                Assert.IsTrue(dp.Reward == 4.0);
            }
        }