Mina, Netty, Twisted learn together (10): Threading model

Source: Internet
Author: User

To develop a high-performance TCP server, it is important to familiarize yourself with the threading model of the framework you are using. MINA, Netty, twisted itself is a high-performance network framework, if coupled with high-efficiency code, to achieve a tall server. But if you don't understand their threading model, it's hard to write high-performance code. The frame itself is more efficient and the program is poorly written, so the overall performance of the server is not too high. Like a computer, CPU is good, memory small hard drive slow heat dissipation, the overall performance is not too high.

The alumni who have played Android development know that there is a very important thread in the Android app: the UI thread (the main thread). The UI thread is responsible for displaying the interface of an Android and interacting with the user. Some of the activity's methods, such as OnCreate, OnStop, and OnDestroy, are all running in the UI thread. However, when writing activity code, it is important to note that there is absolutely no need to write blocking or time-consuming tasks in these methods, and if written in these methods, it will block the UI thread, causing the user interface to be unresponsive and experiencing poor experience. So in Android development, time-consuming or blocking tasks will be open to other threads.

Also in Mina, Netty, twisted, there is a very important thread:IO thread .

Traditional bio-implemented TCP server, especially for TCP long connection, usually to open a thread for each connection, the thread is also a resource of the operating system, so it is difficult to achieve high-performance concurrency. The asynchronous IO implementation of the TCP server, because the IO operation is asynchronous, you can use a thread or a small number of threads to handle a lot of connected IO operations, so only a small number of IO threads to achieve high concurrency of the server.

In the network programming process, there are usually some business logic is more time-consuming, blocking, such as database operations, if the network is not good, coupled with poor database performance, SQL is not optimized, the amount of data is large, a SQL may be executed for a long time. Because the number of IO threads itself is not many, usually only one or several, and if this time-consuming blocking code runs in the IO thread, other things of the IO thread, such as network Read and write, will not work, affecting IO performance and the performance of the entire server.

So, whether you're using Mina, Netty, Twisted, if you have time-consuming tasks, you'll never run in an IO thread, but instead turn on the thread to handle it.

MINA:

In Mina, there are three very important threads: acceptor thread, Connector thread, I/O processor thread.

The following is an introduction to the official documentation:

in MINA, there is three kinds of I/O worker threads in the NIO socket implementation.
acceptor Thread accepts incoming connections, and forwards the connection to the I/O processor thread For read and write operations.
Each socketacceptor creates one acceptor thread. You can ' t configure the number of the acceptor threads.
Connector Thread attempts connections to a remote peer, and forwards the succeeded connection to the I/O processor thread for read and write operations.
Each socketconnector creates one connector thread. You can ' t configure the number of the connector threads, either.
I/O processor thread performs the actual read and write operation until the connection is closed.
Each socketacceptor or socketconnector creates its own I/O processor thread (s). You can configure the number of the I/O processor threads. The default maximum number of the I/O processor threads is the number of the CPU cores + 1.

Acceptor Thread:

This thread is used by the TCP server to receive the new connection and assigns the connection to the I/O processor thread, which is handled by the I/O processor thread for IO operations. Each niosocketacceptor creates a acceptor thread, and the number of threads is not configurable.

Connector Thread:

Used to process the TCP client to connect to the server and assign the connection to the I/O processor thread, which is handled by the I/O processor thread for IO operations. Each niosocketconnector creates a connector thread, and the number of threads is not configurable.

I/O processor thread:

I/O operations for processing TCP connections, such as read, write. The number of threads for I/O processor thread can be configured by Niosocketacceptor or Niosocketconnector construction method, which defaults to +1 of CPU cores.

Since this article mainly introduces the threading model of the TCP server, there is no connector thread. Next, acceptor thread and I/O processor thread process The TCP connection:

The Mina TCP server contains a acceptor thread and multiple I/O processor thread, when a new client connects to the server, the connection is first acquired by the acceptor thread, and the connection is assigned to multiple I/O Processor thread, when the client sends data to the server, the corresponding I/O processor thread is responsible for reading this data, and executing Iofilterchain iofilter and Iohandle.

Due to the limited number of I/O processor thread itself, it is usually a few, but it also handles thousands of connected IO operations, including read, write, encoding and decoding of the Protocol, various filter and business logic in Iohandle, especially business logic, For example, Iohandle messagereceived, if there are time-consuming, blocking tasks, such as querying the database, it will block the I/O processor thread, resulting in the inability to handle other IO events in a timely manner and server performance degradation.

In response to this problem, Mina provides a executorfilterto put the business logic that will take a long time to block I/O processor thread into another thread so that I am not blocking I/O processor Thread, which does not affect IO operations. The executorfilter contains a thread pool, which, by default, is Orderedthreadpoolexecutor, which guarantees that multiple events of the same connection are executed sequentially, You can also use Unorderedthreadpoolexecutor, which does not guarantee the order of execution of events of the same connection, and may execute concurrently. You can choose between them as needed.

public class TCPServer {public static void main (string[] args) throws IOException {Ioacceptor acceptor = new Niosocketacce Ptor (4); Configure the I/O processor thread number Acceptor.getfilterchain (). AddLast ("Codec", New Protocolcodecfilter (new Textlinecodecfactory ())); Acceptor.getfilterchain (). AddLast ("executor", New Executorfilter ()); Take the business logic in Tcpserverhandle to the executorfilter thread pool to execute Acceptor.sethandler (new Tcpserverhandle ()); Acceptor.bind (new Inetsocketaddress (8080));}} Class Tcpserverhandle extends Iohandleradapter {@Overridepublic void messagereceived (iosession session, Object message) Throws Exception {//Suppose there's a perverted SQL to execute 3 seconds thread.sleep (3000);}}

Netty:

When the Netty TCP server starts, it creates two nioeventloopgroup, a boss, and a worker:

Eventloopgroup Bossgroup = new Nioeventloopgroup ();  Eventloopgroup Workergroup = new Nioeventloopgroup ();

Nioeventloopgroup is actually a thread group that can set the number of threads by using the constructor, which defaults to the number of CPU cores. The boss uses the server to receive a new TCP connection, and the boss thread registers the connection with the worker thread after it receives a new connection. The worker thread is used to process IO operations, such as read, write.

The boss thread in Netty is similar to the Mina acceptor thread,work thread and mina I/O processor thread. The difference is that Mina's acceptor thread is a single thread, and Netty's boss is a thread group. In fact, Netty Serverbootstrap can listen to multiple port numbers, if only one port number, then only a boss thread, it is recommended to set the number of bossgroup threads to 1.

Eventloopgroup Bossgroup = new Nioeventloopgroup (1);

When a new TCP client connects to the server, the boss thread will receive the connection and then register the connection with the worker thread, and when the client sends the data to the server, the worker thread is responsible for receiving the data and performing the Channelhandler in Channelpipeline.

Similar to the Mina I/O processor thread, the Netty worker thread itself is not numerous, and the IO event is processed in real time, if there is time-consuming business logic blocking the worker thread, such as executing a time-consuming database query in Channelread. Will cause the IO operation to fail, and the overall performance of the server will be degraded.

In Netty 3, there is a executionhandler, which is an implementation class for Channelhandler that handles time-consuming business logic, similar to Mina's executorfilter, but is removed in Netty 4. So there is no more introduction to Executionhandler.

In Netty 4, you can use Eventexecutorgroup to handle time-consuming business logic:

Package Netty;import Io.netty.bootstrap.serverbootstrap;import Io.netty.channel.channelfuture;import Io.netty.channel.channelhandlercontext;import Io.netty.channel.channelinboundhandleradapter;import Io.netty.channel.channelinitializer;import Io.netty.channel.channelpipeline;import Io.netty.channel.eventloopgroup;import Io.netty.channel.nio.nioeventloopgroup;import Io.netty.channel.socket.socketchannel;import Io.netty.channel.socket.nio.nioserversocketchannel;import Io.netty.handler.codec.linebasedframedecoder;import Io.netty.handler.codec.string.stringdecoder;import Io.netty.util.charsetutil;import Io.netty.util.concurrent.defaulteventexecutorgroup;import Io.netty.util.concurrent.eventexecutorgroup;public class TCPServer {public static void main (string[] args) throws interruptedexception {Eventloopgroup Bossgroup = new Nioeventloopgroup (1);//server listening on a port number, boss thread recommended set to 1EventLoopGroup Workergroup = new Nioeventloopgroup (4); The number of worker threads is set to 4try {serverbootstrap b = new Serverbootstrap (); b. Group (Bossgroup, Workergroup). Channel (Nioserversocketchannel.class). Childhandler (New channelinitializer< Socketchannel> () {//Create a thread group of 16 threads to handle time consuming business logic private Eventexecutorgroup group = new Defaulteventexecutorgroup (16); overridepublic void Initchannel (Socketchannel ch) throws Exception {Channelpipeline pipeline = Ch.pipeline (); Pipeline.addlast (new Linebasedframedecoder);p ipeline.addlast (New Stringdecoder (Charsetutil.utf_8));// Put the business logic in Tcpserverhandler into the Eventexecutorgroup thread group to execute Pipeline.addlast (group, New Tcpserverhandler ());}); Channelfuture f = b.bind (8080). sync (); F.channel (). Closefuture (). sync (); finally {workergroup.shutdowngracefully (); bossgroup.shutdowngracefully ();}}} Class Tcpserverhandler extends Channelinboundhandleradapter {@Overridepublic void Channelread (Channelhandlercontext CTX, Object msg) throws Interruptedexception {//Suppose there's a perverted SQL to execute 3 seconds thread.sleep (3000);}}

Twisted:

The threading model of twisted is the simplest and most brutal: single threaded, or reactor thread . That is, all IO operations, encoding and decoding, business logic, etc. are executed in one thread. In fact, even a single thread, its performance is very high, you can handle a large number of connections at the same time. Programming in a single-threaded environment without the need to consider thread-safe issues. However, a single thread poses a problem, that is, time-consuming business logic, if run in the reactor thread, then other things, such as network IO, will wait until the reactor thread is idle to continue to do, affecting the performance of the server.

The following code executes the time-consuming business logic in a separate thread pool through reactor.callinthread , instead of running in the reactor thread. This will not affect the network IO of the reactor thread. You can set the number of threads for this thread pool through reactor.suggestthreadpoolsize .

#-*-Coding:utf-8–*-import timefrom twisted.internet.protocol import protocolfrom twisted.internet.protocol Import Factoryfrom twisted.internet Import reactor# time-consuming, blocking business logic def logic (data):    print Data    time.sleep (3) # Suppose there's a perverted SQL to execute 3 seconds    class Tcpserverhandle (Protocol):        def datareceived (self, data):        Reactor.callinthread (Logic, data) # Running logic (data) time-consuming task in the thread pool, not running Reactor.suggestthreadpoolsize (8) # in reactor threads # The number of threads that set the thread pool is 8factory = Factory () Factory.protocol = tcpserverhandlereactor.listentcp (8080, Factory) Reactor.run ()

Because of twisted's reactor single-threaded design, many of its code is not thread-safe. So code that executes in a non-reactor thread needs to be aware of thread safety issues. For example, Transport.write is not thread-safe. However, in a non-reactor thread, you can call Reactor.callfromthreadmethod, this method functions as opposed to callinthread, which puts a function from another thread into the reactor thread. However, it is important to note that the function called by Reactor.callfromthread is running in the reactor thread, and if it is time consuming, it will also block the reactor thread, affecting IO.

#-*-Coding:utf-8–*-import timefrom twisted.internet.protocol import protocolfrom twisted.internet.protocol Import Factoryfrom twisted.internet Import reactor# Non-thread-safe Code def notthreadsafe ():    print "Notthreadsafe" # time-consuming, blocking business logic def Logic (data):    print Data    time.sleep (3) # Suppose there's a perverted SQL to execute 3 seconds    Reactor.callfromthread (notthreadsafe) # Run Notthreadsafe ()    class Tcpserverhandle (Protocol) in the reactor thread:        def datareceived (self, data):        Reactor.callinthread (logic, data) # Running logic (data) time-consuming task in a thread pool, not running Reactor.suggestthreadpoolsize (8) in Reactor threads # The number of threads that set the thread pool is 8factory = Factory () Factory.protocol = tcpserverhandlereactor.listentcp (8080, Factory) Reactor.run ()

In addition, many convenient functions are available in the twisted.internet.threads. For example Threads.defertothreadUsed to execute a time-consuming task in a thread pool, unlike Reactor.callinthread, whose return value is the deferred type, which can be processed by adding a callback function to the result (return value) of the time-consuming task.

#-*-Coding:utf-8–*-import timefrom twisted.internet.protocol import protocolfrom twisted.internet.protocol Import Factoryfrom twisted.internet Import reactor, threads# time-consuming, blocking business logic def logic (data):    print Data    time.sleep (3) # Suppose there's a perverted SQL to execute 3 seconds    return "Success" # callback function def logicsuccess (result):    # result is the return value of the logic function, which is "success"    Print ResultClass Tcpserverhandle (Protocol):        def datareceived (self, data):        D = threads.defertothread (logic, Data) # Put the time-consuming business logic (data) into the thread pool to run, Defertothread return value type is deferred        d.addcallback (logicsuccess) # Add callback function Reactor.suggestthreadpoolsize (8) # Sets the thread pool's number of threads to 8factory = Factory () Factory.protocol = TCPSERVERHANDLEREACTOR.LISTENTCP (8080, Factory) Reactor.run ()


Fork Brother reproduced please indicate the source: http://blog.csdn.net/xiao__gui/article/details/40146351



Mina, Netty, Twisted learn together (10): Threading model

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.