Multithreading in Photon

What is the article about

In this article, we will talk about server-side multithreading.





  • how is it implemented





  • how is used





  • what can be done





  • what we ourselves invented





All these questions are relevant only if you are developing something directly for the server side - modifying the SDK code, writing your own plugin, or even doing something of your own.





How does Photon deal with multithreading?

The photon server application accepts requests from multiple client connections. I will call such connections peers . These requests form queues. One for each feast. If peers are connected to the same room, their queues are combined into one - the room queue. There are up to several thousand such rooms, and their request queues are also processed in parallel.





As a basis for the implementation of task queues in Photon, the retlang library was taken, which was developed on the basis of the Jetlang library.





Why not using Task and async / await

Therefore, there are the following considerations:





  1. Photon started developing before these things appeared.





  2. , , - . , , , GC , . , .





  3. TaskScheduler, , - .





Fiber?

, . - FIFO. , multiple writers-single reader. , , , .. . .





Photon , PoolFiber, . IFiber. .





  • ThreadFiber - IFiber, . .





  • PoolFiber - IFiber, .NET. . . ( ).





  • FormFiber/DispatchFiber - IFiber, WinForms/WPF. FormFiber/DispatchFiber Invoke BeginInvoke .





  • StubFiber - . , (races) . .





PoolFiber

PoolFiber. , . :





  1. . ThreadPool.QueueUserWorkItem. - .





  2. , , ThreadPool.QueueUserWorkItem, . . , .





.. , , . , , () . - , , .





PoolFiber

Photon PoolFiber. , . , , . .. PoolFiber.Stop . .





. -. , , , .





:









  • ,





  • , .





:





//    
fiber.Enqueue(()=>{some action code;});

      
      



//    ,    10 
var scheduledAction = fiber.Schedule(()=>{some action code;}, 10_000);
...
//  
scheduledAction.Dispose()

      
      



//    ,    10    5
var scheduledAction = fiber.Schedule(()=>{some action code;}, 10_000, 5_000);
...
//  
scheduledAction.Dispose()

      
      



, - , fiber.Schedule. .





Executors

. , . Execute(Action a)



Execute(List<Action> a)



. PoolFiber . .. . . DefaultExecutor. :





        public void Execute(List<Action> toExecute)
        {
            foreach (var action in toExecute)
            {
                Execute(action);
            }
        }

        public void Execute(Action toExecute)
        {
            if (_running)
            {
                toExecute();
            }
        }

      
      



. 'action' toExecute . FailSafeBatchExecutor, try/catch. , . , , github.





BeforeAfterExecutor

, . BeforeAfterExecutor. "" . , FailSafeBatchExecutor. BeforeAfterExecutor . :





public BeforeAfterExecutor(Action beforeExecute, Action afterExecute, IExecutor executor = null)

      
      



. . . / , , . , .





:






var beforeAction = ()=>
{
  log4net.ThreadContext.Properties["Meta1"] = "value";
};

var afterAction = () => ThreadContext.Properties.Clear();

// 
var e = new BeforeAfterExecutor(beforeAction, afterAction);

// PoolFiber
var fiber = new PoolFiber(e);

      
      



- , fiber, log4net Meta1 value.





ExtendedPoolFiber ExtendedFailSafeExecutor

, retlang, . . , . . PoolFiber ( , .NET). , , HTTP . :





  1. event;





  2. , , , , event ;





  3. event.





. , , , , event. . . , .





ExtendedPoolFiber ExtendedFailSafeExecutor. . , . , Pause. ( ) . :





  1. Resume





  2. ( Pause) Resume , , .





, , HTTP . , . Resume , .





, ThreadFiber .





IFiberAction

IFiberAction - GC. .NET. , IFiberAction. , . GC





IFiberAction :





public interface IFiberAction
{
    void Execute()
    void Return()
}
      
      



Execute , . Return Execute, .





:





public class PeerHandleRequestAction : IFiberAction
{
    public static readonly ObjectPool<PeerHandleRequestAction> Pool = initialization;
    public OperationRequest Request {get; set;}
    public PhotonPeer Peer {get; set;}
    
    public void Execute()
    {
        this.Peer.HandleRequest(this.Request);
    }
    
    public void Return()
    {
        this.Peer = null;
        this.Request = null;
        
        Pool.Return(this);
    }
}

//     

var action = PeerHandleRequestAction.Pool.Get();
action.Peer = peer;
action.Request = request;

peer.Fiber.Enqueue(action);

      
      



, . , . , PoolFiber . PoolFiber .NET. PoolFiber , . , ExtendedPoolFiber.





Executors implementing the IExecutor interface are directly involved in the execution of tasks in fibers . DefaultExecutor is good for everyone, but in case of an exception, it loses the entire remainder of the tasks that were transferred to it for execution. FailSafeExecutor appears to be a smart choice in this regard . If you need to perform some action before and after the execution of a batch of tasks by the executor, BeforeAfterExecutor may come in handy








All Articles