Netty源码(四)NioEventLoop对IO事件的处理

NioEventLoop的运行

wakeup

protected void wakeup(boolean inEventLoop) {
   
   
	// 因为wakeup操作代价较高,避免频繁地调用wakeup,使用cas来减少调用次数
	// inEventLoop代表当前是否在eventloop中,如果为true,代表eventloop正在运行,所以不需要wakeup
	// wakeUp有延迟生效的特点,如果在调用wakeup的时候,selector并没有因为执行select方法而阻塞,那么这次wakeup会直接使下一次select方法的调用直接返回
    if (!inEventLoop && wakenUp.compareAndSet(false, true)) {
   
   
        selector.wakeup();
    }
}

run

一直执行直到eventLoop关闭,每次循环都会执行下面三件事

  1. Selector.select 等待io事件
  2. 处理io时间
  3. 处理普通任务和延时任务
protected void run() {
   
   
    for (;;) {
   
   
        try {
   
   
        	// selectStrategy用来控制select行为
        	// 
            switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
   
   
                case SelectStrategy.CONTINUE:
                    continue;
                case SelectStrategy.SELECT:
                	// 将wakenup标记设置为false,进行阻塞select
                    select(wakenUp.getAndSet(false));

                    // 'wakenUp.compareAndSet(false, true)' is always evaluated
                    // before calling 'selector.wakeup()' to reduce the wake-up
                    // overhead. (Selector.wakeup() is an expensive operation.)
                    //
                    // However, there is a race condition in this approach.
                    // The race condition is triggered when 'wakenUp' is set to
                    // true too early.
                    //
                    // 'wakenUp' is set to true too early if:
                    // 1) Selector is waken up between 'wakenUp.set(false)' and
                    //    'selector.select(...)'. (BAD)
                    // 2) Selector is waken up between 'selector.select(...)' and
                    //    'if (wakenUp.get()) { ... }'. (OK)
                    //
                    // In the first case, 'wakenUp' is set to true and the
                    // following 'selector.select(...)' will wake up immediately.
                    // Until 'wakenUp' is set to false again in the next round,
                    // 'wakenUp.compareAndSet(false, true)' will fail, and therefore
                    // any attempt to wake up the Selector will fail, too, causing
                    // the following 'selector.select(...)' call to block
                    // unnecessarily.
                    //
                    // To fix this problem, we wake up the selector again if wakenUp
                    // is true immediately after selector.select(...).
                    // It is inefficient in that it wakes up the selector for both
                    // the first case (BAD - wake-up required) and the second case
                    // (OK - no wake-up required).
					// 看下面的图了解为什么会有这段代码
					// 判断是否调用了wakeUp方法
                    if (wakenUp.get()) {
   
   
                        selector.wakeup();
                    }
                    // fall through
                default:
            }

            cancelledKeys = 0;
            needsToSelectAgain = false;
            final int ioRatio = this.ioRatio;
            if (ioRatio == 100) {
   
   
                try {
   
   
                	// 处理io事件
                    processSelectedKeys();
                } finally {
   
   
                	// 运行普通任务和定时任务,不会限制时间
                    // Ensure we always run tasks.
                    runAllTasks();
                }
            } else {
   
   
                final long ioStartTime = System.nanoTime();
                try {
   
   
                	// 处理io事件
                    processSelectedKeys();
                } finally {
   
   
                    // Ensure we always run tasks.
                    // 处理io事件的时间
                    final long ioTime = System.nanoTime() - ioStartTime;
                    // 运行普通任务和定时任务,会限制时间
                    // 使用处理io事件的时间来计算执行普通任务和定时任务的时间
                    runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
                }
            }
        } catch (Throwable t) {
   
   
            handleLoopException(t);
        }
        // Always handle shutdown even if the loop processing threw an exception.
        try {
   
   
            if (isShuttingDown()) {
   
   
                closeAll();
                if (confirmShutdown()) {
   
   
                    return;
                }
            }
        } catch (Throwable t) {
   
   
            handleLoopException(t);
        }
    }
}

在这里插入图片描述

SelectStrategy

SelectStategy用来控制select的行为

public interface SelectStrategy {
   
   

    /**
     * Indicates a blocking select should follow.
     */
    int SELECT = -1;
    /**
     * Indicates the IO loop should be retried, no blocking select to follow directly.
     */
    int CONTINUE = -2;

    /**
     * The {@link SelectStrategy} can be used to steer the outcome of a potential select
     * call.
     *
     * @param selectSupplier The supplier with the result of a select result.
     * @param hasTasks true if tasks are waiting to be processed.
     * @return {@link #SELECT} if the next step should be blocking select {@link #CONTINUE} if
     *         the next step should be to not select but rather jump back to the IO loop and try
     *         again. Any value >= 0 is treated as an indicator that work needs to be done.
     */
    int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception;
}

主要方法是calculateStrategy,返回值是SELECT或者CONTINUE

  1. SELECT表示进行阻塞select
  2. CONTINUE代表重试
  3. 其他值,跳过select阶段,处理io事件

Netty默认提供的是DefaultSelectStrategy

final class DefaultSelectStrategy implements SelectStrategy {
   
   
    static final SelectStrategy INSTANCE = new DefaultSelectStrategy();

    private DefaultSelectStrategy() {
   
    }

    @Override
    public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception {
   
   
    	// 如果当前有任务,返回selectSupplier.get的值
    	// 没有任务,返回SELECT,执行selector.select
        return hasTasks ? selectSupplier.get() : SelectStrategy.SELECT;
    }
}

NioEventLoop默认使用的IntSupplier代码如下

private final IntSupplier selectNowSupplier = new IntSupplier() {
   
   
    @Override
    public int get() throws Exception {
   
   
    	// 调用NioEventLoop的selectNow方法,返回当前已经就绪的事件个数
        return selectNow();
    }
};

selectNow

int selectNow() throws IOException {
   
   
    try {
   
   
        return selector.selectNow();
    } finally {
   
   
        // restore wakeup state if needed
        if (wakenUp.get()) {
   
   
            selector.wakeup();
        }
    }
}

select

private void select(boolean oldWakenUp) throws IOException {
   
   
    Selector selector = this.selector;
    try {
   
   
    	// 用来记录连续空循环的次数,当连续空循环的次数达到阈值时,为了避免cpu100%,创建新的selector
        int selectCnt = 0;
        long currentTimeNanos = System.nanoTime();
        // 定时任务的截止时间
        long selectDeadLineNanos = currentTimeNanos + delayNanos(currentTimeNanos);

        for (;;) {
   
   
        	// <1> 计算select剩余时间,判断定时任务的截止时间是否快到了
            long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值