`
Donald_Draper
  • 浏览: 984825 次
社区版块
存档分类
最新评论

WindowsSelectorImpl解析一(FdMap,PollArrayWrapper)

    博客分类:
  • NIO
阅读更多
Channel接口定义:http://donald-draper.iteye.com/blog/2369111
AbstractInterruptibleChannel接口定义:http://donald-draper.iteye.com/blog/2369238
SelectableChannel接口定义:http://donald-draper.iteye.com/blog/2369317
SelectionKey定义:http://donald-draper.iteye.com/blog/2369499
SelectorProvider定义:http://donald-draper.iteye.com/blog/2369615
AbstractSelectableChannel定义:http://donald-draper.iteye.com/blog/2369742
NetworkChannel接口定义:http://donald-draper.iteye.com/blog/2369773
ServerSocketChannel定义:http://donald-draper.iteye.com/blog/2369836
Selector定义:http://donald-draper.iteye.com/blog/2370015
AbstractSelector定义:http://donald-draper.iteye.com/blog/2370138
SelectorImpl分析 :http://donald-draper.iteye.com/blog/2370519
引言:
在上一篇文章中,我们看了SelectorImpl的相关key集合和方法,先来回顾一下:
     SelectorImpl有4个集合分别为就绪key集合,key集合,key集合的代理publicKeys及就绪key集合的代理publicSelectedKeys;实际是两个集合就绪key集合和key集合,publicSelectedKeys和publicKeys是其他线程访问上述两个集合的代理。
     SelectorImpl构造的时候,初始化选择器提供者SelectorProvider,创建就绪key集合和key集合,然后初始化就绪key和key集合的代理,初始化过程为,如果nio包的JDK版本存在bug问题,则就绪key和key集合的代理集合直接引用就绪key和key集合。否则将当前key集合包装成不可修改的代理集合publicKes,将就绪key集合包装成容量固定的集合publicSelectedKeys。
其他线程获取选择器的就绪key和key集合,实际上返回的是key集合的代理publicKeys和就绪key集合的代理publicSelectedKeys。
     select方法的3中操作形式,实际上委托给为lockAndDoSelect方法,方法实际上是同步的,可安全访问,获取key集合代理publicKeys和就绪key代理集合publicSelectedKeys,然后交给doSelect(long l)方法,这个方法为抽象方法,待子类扩展。实际的关闭选择器操作implCloseSelector方法,首先唤醒等待选择操作的线程,唤醒方法wakeup待实现,同步选择器,就绪key和key集合的代理publicKeys,publicSelectedKeys,调用implClose完成实际的关闭通道工作,待子类实现。
     可选通道注册方法,首先注册的通道必须是AbstractSelectableChannel类型,并且是SelChImpl实例。更具可选择通道和选择器构造选择key,设置选择key的附加物,同步key集合代理,调用implRegister方法完成实际的注册工作,implRegister方法待子类实现。
     processDeregisterQueue方法,主要是遍历取消key集合,反注册取消key,实际的反注册工作由implDereg方法,implDereg方法待子类扩展。成功,则从集合中移除。
今天我们来看的选择器的具体实现WindowsSelectorProvider,在这篇文章中,我们要关注的是这几个方法,选择操作中的doSelect(long l),注册key操作的implRegister方法,处理取消key集合方法中implDereg方法和唤醒方法wakeup。
我们先从打开选择器开始
//Selector
  public static Selector open() throws IOException {
        return SelectorProvider.provider().openSelector();
    }

//SelectorProvider
  
 public static SelectorProvider provider() {  
            synchronized (lock) {  
                if (provider != null)  
                    return provider;  
           //在与当前线程相同访问控制权限的环境中,加载SelectorProvider实例  
                return AccessController.doPrivileged(  
                    new PrivilegedAction<SelectorProvider>() {  
                        public SelectorProvider run() {  
                                if (loadProviderFromProperty())  
                        //获取系统配置的SelectorProvider  
                                    return provider;  
                                if (loadProviderAsService())  
                         //获取类加载路径下的SelectorProvider  
                                    return provider;  
                        //加载默认的SelectorProvider  
                                provider = sun.nio.ch.DefaultSelectorProvider.create();  
                                return provider;  
                            }  
                        });  
            }  
    }  

来看默认的DefaultSelectorProvider
//DefaultSelectorProvider
 
  package sun.nio.ch;  
      
    import java.nio.channels.spi.SelectorProvider;  
      
    // Referenced classes of package sun.nio.ch:  
    //            WindowsSelectorProvider  
      
    public class DefaultSelectorProvider  
    {  
        private DefaultSelectorProvider()  
        {  
        }  
        public static SelectorProvider create()  
        {  
            //默认的WindowsSelectorProvider  
            return new WindowsSelectorProvider();  
        }  
    }  

从上面了可以看出选择器的默认实现为WindowsSelectorImpl,下面我们来具体看一下,先看一下变量的定义,具体每个变量及集合含义我们现在可能不完全解释清楚,一般从字面上可以看出它的意思,对于不能完全理解的变量,我们在后面的文章中,再纠正。
final class WindowsSelectorImpl extends SelectorImpl
{
    private final int INIT_CAP = 8;//选择key集合,key包装集合初始化容量
    private static final int MAX_SELECTABLE_FDS = 1024;//最大选择key数量
    private SelectionKeyImpl channelArray[];//选择器关联通道集合
    private PollArrayWrapper pollWrapper;//存放所有文件描述对象(选择key,唤醒管道的源与sink通道)的集合
    private int totalChannels;//注册到选择的通道数量
    private int threadsCount;//选择线程数
    private final List threads = new ArrayList();//选择操作线程集合
    private final Pipe wakeupPipe = Pipe.open();//唤醒等待选择操操的管道
    private final int wakeupSourceFd;//唤醒管道源通道文件描述
    private final int wakeupSinkFd;//唤醒管道sink通道文件描述
    private Object closeLock;//选择器关闭同步锁
    private final FdMap fdMap = new FdMap();//存放选择key文件描述与选择key映射关系的Map
    private final SubSelector subSelector = new SubSelector();//子选择器
    private long timeout;//超时时间,具体什么意思,现在还没明白,在后面在看
    private final Object interruptLock = new Object();//中断同步锁,在唤醒选择操作线程时,用于同步
    private volatile boolean interruptTriggered;//是否唤醒等待选择操的线程
    private final StartLock startLock = new StartLock();//选择操作开始锁
    private final FinishLock finishLock = new FinishLock();//选择操作结束锁
    private long updateCount;//更新数量,具体什么意思,现在还没明白,在后面在看
    static final boolean $assertionsDisabled = !sun/nio/ch/WindowsSelectorImpl.desiredAssertionStatus();
    static 
    {
        //加载nio,net资源库
        Util.load();
    } 
}

//Util
static void load()
    {
label0:
        {
            synchronized(sun/nio/ch/Util)
            {
                if(!loaded)
                    break label0;
            }
            return;
        }
        loaded = true;
	//在与当前线程相同访问控制权限的情况下,加载net和nio资源库
        AccessController.doPrivileged(new LoadLibraryAction("net"));
        AccessController.doPrivileged(new LoadLibraryAction("nio"));
        IOUtil.initIDs();
        local;
        JVM INSTR monitorexit ;
          goto _L1
        exception;
        throw exception;
_L1:
    }


//这个我们先放在这里,我们慢慢解开选择的构造
 WindowsSelectorImpl(SelectorProvider selectorprovider)
        throws IOException
    {
        super(selectorprovider);
        channelArray = new SelectionKeyImpl[8];
        totalChannels = 1;
        threadsCount = 0;
        closeLock = new Object();
        interruptTriggered = false;
        updateCount = 0L;
        pollWrapper = new PollArrayWrapper(8);
        wakeupSourceFd = ((SelChImpl)wakeupPipe.source()).getFDVal();
        SinkChannelImpl sinkchannelimpl = (SinkChannelImpl)wakeupPipe.sink();
        sinkchannelimpl.sc.socket().setTcpNoDelay(true);
        wakeupSinkFd = sinkchannelimpl.getFDVal();
        pollWrapper.addWakeupSocket(wakeupSourceFd, 0);
    }

为了更好的理解fdMap和pollWrapper作用我们来看一下这两个集合的定义:
先看FdMap
//key与key描述符映射关系Map
 private static final class FdMap extends HashMap
    {
        static final long serialVersionUID = 0L;
        private FdMap()
        {
        }
	//根据key文件描述id获取key
        private MapEntry get(int i)
        {
            return (MapEntry)get(new Integer(i));
        }
	//添加key
        private MapEntry put(SelectionKeyImpl selectionkeyimpl)
        {
            return (MapEntry)put(new Integer(selectionkeyimpl.channel.getFDVal()), new MapEntry(selectionkeyimpl));
        }
	//移除选择key
        private MapEntry remove(SelectionKeyImpl selectionkeyimpl)
        {
            Integer integer = new Integer(selectionkeyimpl.channel.getFDVal());
            MapEntry mapentry = (MapEntry)get(integer);
            if(mapentry != null && mapentry.ski.channel == selectionkeyimpl.channel)
                return (MapEntry)remove(integer);
            else
                return null;
        }
    }
    

//MapEntry
 
  private static final class MapEntry
    {
        SelectionKeyImpl ski;//选择key
	//这两个计数器,现在还不知道干什么用的,后备碰到再说
        long updateCount;//操作事件更新计数器
        long clearedCount;操作事件清除计数器
        MapEntry(SelectionKeyImpl selectionkeyimpl)
        {
            updateCount = 0L;
            clearedCount = 0L;
            ski = selectionkeyimpl;
        }
    }

从上面可以看出FdMap主要是存储选择key的,FdMap实际上是一个HashMap,key为选择key的文件描述id,value为MapEntry,MapEntry为选择key的包装Entry,里面含有更新计数器updateCount和清除计数器clearedCount。

再看PollArrayWrapper,
PollArrayWrapper,我们可以这么理解为本地内存空间管理器主要是
将文件描述(选择key,唤醒管道的source和sink通道)信息及相关的兴趣操作事件存储在本地内存空间中。PollArrayWrapper是通过AllocatedNativeObject来操作底层存储空间
//PollArrayWrapper
class PollArrayWrapper
{
    private AllocatedNativeObject pollArray;//底层内存空间
    long pollArrayAddress;//内存空间起始位置
    private static final short FD_OFFSET = 0;文件描述id开始位置
    private static final short EVENT_OFFSET = 4;//兴趣事件开始位置
    static short SIZE_POLLFD = 8;//文件描述id的长度int(4)+操作事件长度4
    //这些事件当前不能明白意思,只是简单的猜测,理解的网友给我留言,谢谢
    static final short POLLIN = 1;//添加事件
    static final short POLLOUT = 4;//拉取事件
    static final short POLLERR = 8;//操作错误
    static final short POLLHUP = 16;//操作挂起
    static final short POLLNVAL = 32;
    static final short POLLREMOVE = 2048;//移除
    static final short POLLCONN = 2;//
    private int size;
    //创建i容量的文件描述管理器
    PollArrayWrapper(int i)
    {
        int j = i * SIZE_POLLFD;
	//分配内存空间
        pollArray = new AllocatedNativeObject(j, true);
	//初始化空间起始地址
        pollArrayAddress = pollArray.address();
        size = i;//初始化容量
    }
}

//已分配的本地空间
class AllocatedNativeObject extends NativeObject
{
    AllocatedNativeObject(int i, boolean flag)
    {
        super(i, flag);
    }
    //释放本地对象空间
    synchronized void free()
    {
        //如果已分配的地址不为0,则释放空间
        if(allocationAddress != 0L)
        {
            unsafe.freeMemory(allocationAddress);
            allocationAddress = 0L;
        }
    }
}


//NativeObject,本地内存管理对象
package sun.nio.ch;
import java.nio.ByteOrder;
import sun.misc.Unsafe;

class NativeObject
{
    protected static final Unsafe unsafe = Unsafe.getUnsafe();
    protected long allocationAddress;//已分配的地址空间
    private final long address;//空间起始位置
    private static ByteOrder byteOrder = null;
    private static int pageSize = -1;//内存分页大小
    static final boolean $assertionsDisabled = !sun/nio/ch/NativeObject.desiredAssertionStatus();
    NativeObject(long l)
    {
        allocationAddress = l;
        address = l;
    }
    NativeObject(long l, long l1)
    {
        allocationAddress = l;
        address = l + l1;
    }
    //分配i大小的内存空间,flag为是否分配内存页
    protected NativeObject(int i, boolean flag)
    {
        if(!flag)
        {
            allocationAddress = unsafe.allocateMemory(i);
            address = allocationAddress;
        } else
        {
            int j = pageSize();
            long l = unsafe.allocateMemory(i + j);
            allocationAddress = l;//已分配内存空间
            address = (l + (long)j) - (l & (long)(j - 1));//空间起始位置
        }
    }
    //获取内存分页大小
    static int pageSize()
    {
        if(pageSize == -1)
            pageSize = unsafe.pageSize();
        return pageSize;
    }
}

//再来看PollArrayWrapper的其他方法
//添加选择key到文件描述包装集合i索引上
void addEntry(int i, SelectionKeyImpl selectionkeyimpl)
{
   //委托给putDescriptor
    putDescriptor(i, selectionkeyimpl.channel.getFDVal());
}

//将文件描述id-j放在索引i上
void putDescriptor(int i, int j)
{
    //委托给pollArray
    pollArray.putInt(SIZE_POLLFD * i + 0, j);
}

//NativeObject
//将文件描述id-j,放在地址i上
final void putInt(int i, int j)
{
    unsafe.putInt((long)i + address, j);
}

存放索引i文件描述信息的兴趣操作事件
 void putEventOps(int i, int j)
    {
        //委托给pollArray
        pollArray.putShort(SIZE_POLLFD * i + 4, (short)j);
    }

//NativeObject
//存放文件描述的兴趣操作事件,放在地址i上
   final void putShort(int i, short word0)
    {
        unsafe.putShort((long)i + address, word0);
    }

//获取索引i的文件描述id
int getDescriptor(int i)
{
    return pollArray.getInt(SIZE_POLLFD * i + 0);
}

//NativeObject
    final short getShort(int i)
    {
        return unsafe.getShort((long)i + address);
    }


//获取索引i的文件描述id关注的兴趣操作事件
int getEventOps(int i)
{
    return pollArray.getShort(SIZE_POLLFD * i + 4);
}

//NativeObject
    final short getShort(int i)
    {
        return unsafe.getShort((long)i + address);
    }


从上面可以好像看出一点门道,PollArrayWrapper作用即存放选择key和选择key关注的
事件,用选择key的文件描述id,表示选择key,文件描述id为int,所以占4个字节,选择key
的兴趣操作事件也为int,即4个字节,所以SIZE_POLLFD为8,文件描述id开始位置FD_OFFSET为0,兴趣事件开始位置EVENT_OFFSET为4;FD_OFFSET和EVENT_OFFSET都是相对于SIZE_POLLFD的。


再来看其他操作
//PollArrayWrapper,替换j索引上的文件描述信息为i索引对应的文件描述信息
void replaceEntry(PollArrayWrapper pollarraywrapper, int i, PollArrayWrapper pollarraywrapper1, int j)
{
    pollarraywrapper1.putDescriptor(j, pollarraywrapper.getDescriptor(i));
    pollarraywrapper1.putEventOps(j, pollarraywrapper.getEventOps(i));
}

添加唤醒管道的source通道文件描述符
void addWakeupSocket(int i, int j)
{
    putDescriptor(j, i);
    //等待唤醒描述符关注的事件是添加事件POLLIN
    putEventOps(j, 1);
}

我猜测一下这个意思,PollArrayWrapper同时存储唤醒等待选择操作的选择器的通道和唤醒通道关注事件即通道注册选择器事件,即添加选择key事件。当有通道注册到选择器,则唤醒通道,唤醒等待选择操作的选择器。
//PollArrayWrapper
//释放内存空间
void free()
{
    pollArray.free();
}

//AllocatedNativeObject
synchronized void free()
{
    if(allocationAddress != 0L)
    {
        unsafe.freeMemory(allocationAddress);
        allocationAddress = 0L;
    }
}

//PollArrayWrapper
//增加i个存储文件描述及相应的兴趣操作事件内存块
void grow(int i)
{
    //重新创建文件描述集合
    PollArrayWrapper pollarraywrapper = new PollArrayWrapper(i);
    //将原始文件描述及相关兴趣操作事件,移到新的集合中
    for(int j = 0; j < size; j++)
        replaceEntry(this, j, pollarraywrapper, j);
    //释放旧集合的空间
    pollArray.free();
    //更新pollArray,容量及起始地址
    pollArray = pollarraywrapper.pollArray;
    size = pollarraywrapper.size;
    pollArrayAddress = pollArray.address();
}

看完这两个集合,再来看WindowsSelectorImpl的构造
WindowsSelectorImpl(SelectorProvider selectorprovider)
        throws IOException
    {
        super(selectorprovider);
	//创建选择器关联通道数组,实际存的为选择key
        channelArray = new SelectionKeyImpl[8];
        totalChannels = 1;
        threadsCount = 0;
        closeLock = new Object();//关闭锁
        interruptTriggered = false;
        updateCount = 0L;
        pollWrapper = new PollArrayWrapper(8);
        wakeupSourceFd = ((SelChImpl)wakeupPipe.source()).getFDVal();//唤醒管道源通道文件描述id
        SinkChannelImpl sinkchannelimpl = (SinkChannelImpl)wakeupPipe.sink();//唤醒管道sink通道
        sinkchannelimpl.sc.socket().setTcpNoDelay(true);//设置唤醒管道sink通道的Socket为无延时
        wakeupSinkFd = sinkchannelimpl.getFDVal();
	//将唤醒管道的源通道文件描述id添加pollWrapper的索引0位置上
        pollWrapper.addWakeupSocket(wakeupSourceFd, 0);
    }

WindowsSelectorImpl默认加载net和nio资源库;WindowsSelectorImpl内锁4个,分别为关闭锁closeLock,中断锁interruptLock,startLock,finishLock后面两个的作用,目前还不清楚,后面再说;一个唤醒管道,作用尚不明确;一个注册到选择器的通道计数器totalChannels;updateCount计数器作用,尚不明确;通道集合channelArray,存放的元素实际为通道关联的选择key;pollWrapper用于存储选择key和相应的兴趣事件,及唤醒管道的源通道,唤醒管道的源通道存放在pollWrapper的索引0位置上。

关于唤醒管道的作用,现在还不是太清楚,在后面的文章中在具体讲解其作用。
我们要关注的几个方法为
1.注册key操作的implRegister方法
2.处理取消key集合方法中implDereg方法
3.选择操作中的doSelect(long l)
4.唤醒方法wakeup
5.实际关闭选择通道方法implClose
由于篇幅问题,这几个方法,放在下一篇文章中再讲

总结:
      WindowsSelectorImpl默认加载net和nio资源库;WindowsSelectorImpl内锁4个,分别为关闭锁closeLock,中断锁interruptLock,startLock,finishLock后面两个的作用,目前还不清楚,后面再说;一个唤醒管道,作用尚不明确;一个注册到选择器的通道计数器totalChannels;updateCount计数器作用,尚不明确;通道集合channelArray,存放的元素实际为通道关联的选择key;pollWrapper用于存储选择key和相应的兴趣事件,及唤醒管道的源通道,唤醒管道的源通道存放在pollWrapper的索引0位置上。
     FdMap主要是存储选择key的,FdMap实际上是一个HashMap,key为选择key的文件描述id,value为MapEntry,MapEntry为选择key的包装Entry,里面含有更新计数器updateCount和清除计数器clearedCount。
     PollArrayWrapper存放选择key和通道及其相关的操作事件。PollArrayWrapper通过AllocatedNativeObject来存储先关的文件描述及其兴趣事件,AllocatedNativeObject
为已分配的底层内存空间,AllocatedNativeObject的内存主要NativeObject来分配,NativeObject实际是通过Unsafe来分配内存。PollArrayWrapper作用即存放选择key和选择key关注的事件,用选择key的文件描述id,表示选择key,文件描述id为int,所以占4个字节,选择key的兴趣操作事件也为int,即4个字节,所以SIZE_POLLFD为8,文件描述id开始位置FD_OFFSET为0,兴趣事件开始位置EVENT_OFFSET为4;FD_OFFSET和EVENT_OFFSET都是相对于SIZE_POLLFD的。PollArrayWrapper同时存储唤醒等待选择操作的选择器的通道和唤醒通道关注事件即通道注册选择器事件,即添加选择key事件。当有通道注册到选择器,则唤醒通道,唤醒等待选择操作的选择器。

WindowsSelectorImpl解析二(选择操作,通道注册,通道反注册,选择器关闭等):
http://donald-draper.iteye.com/blog/2370862
1
1
分享到:
评论
1 楼 ezlhq 2018-07-27  
关于 PollArrayWrapper 状态含义猜测:

参考 SocketChannelImpl#translateAndSetInterestOps:
(http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/db6e25fee0f7/src/share/classes/sun/nio/ch/SocketChannelImpl.java)
 public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
        int newOps = 0;
        if ((ops & SelectionKey.OP_READ) != 0)
            newOps |= PollArrayWrapper.POLLIN;
        if ((ops & SelectionKey.OP_WRITE) != 0)
            newOps |= PollArrayWrapper.POLLOUT;
        if ((ops & SelectionKey.OP_CONNECT) != 0)
            newOps |= PollArrayWrapper.POLLCONN;
        sk.selector.putEventOps(sk, newOps);
    }

可以看出来,POLLIN是read事件,POLLOUT是write事件,POLLCONN是connection事件

参考 ServerSocketChannelImpl#translateAndSetInterestOps:
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/1a3de3cdc684/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
    public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
        int newOps = 0;

        // Translate ops
        if ((ops & SelectionKey.OP_ACCEPT) != 0)
            newOps |= PollArrayWrapper.POLLIN;
        // Place ops into pollfd array
        sk.selector.putEventOps(sk, newOps);
    }


可以看出来 POLLIN是ACCEPT事件。


其他事件还没看到

相关推荐

    Java-NIO-Netty框架学习

    资源名称:Java-NIO-Netty框架学习资源目录:【】Netty5.0架构剖析和源码解读【】Netty5用户指南【】Netty_in_Action(第五版-目录修正版)【】Netty_in_Action_v08_MEAP【】Netty_in_Action_v10_MEAP【】Netty_代码...

    Java NIO 细节也精彩

    ### Java NIO 的精彩细节解析 #### 一、Selector的Wakeup原理 ##### 1.1 背景介绍 在Java NIO (Non-blocking I/O)中,`Selector` 是核心组件之一,用于监控多个`Channel`上的I/O事件(如可读、可写等)。`...

    中式汉堡市场调研报告:2023年市场规模约为1890亿元

    汉堡市场调研报告:2023年市场规模约为1890亿元 在快节奏的现代生活中,汉堡以其便捷、快速且标准化的特点,成为了大众日常饮食的重要选择。然而,随着消费者对健康、口味和文化认同感的追求日益提升,传统西式汉堡已难以满足所有消费者的需求。在此背景下,中式汉堡应运而生,以其独特的口味和文化内涵,迅速赢得了市场的青睐。那么,中式汉堡市场究竟蕴含着怎样的增长潜力?又该如何把握这一市场机遇呢? 市场概况: 近年来,中国西式快餐市场规模持续扩大,2023年已达到约3687.8亿元。其中,汉堡作为西式快餐的代表之一,市场规模约为1890亿元,占据了西式快餐最大的市场份额。值得注意的是,中式汉堡品牌异军突起,凭借其独特的口味和文化内涵,迅速在市场上站稳脚跟。截至2024年11月,全国中式汉堡门店数已近2万家,展现出强劲的增长势头。 技术创新与趋势: 中式汉堡的成功,离不开技术创新和趋势把握。一方面,中式汉堡品牌通过结合中式烹饪方式,推出了更符合中国消费者口味的产品,如加入秘制酱料、使用传统烹饪技艺等,使汉堡更加美味可口。另一方面,中式汉堡品牌还注重数智化转型,通过运用大数据、人工智能等先进技术,实现精

    基于MATLAB的导航科学计算库

    * GPS IMU经典15维ESKF松组合 * VRU/AHRS姿态融合算法 * 捷联惯导速度位置姿态解算例子 * UWB IMU紧组合融合 * 每个例子自带数据集

    Docker以及Docker-Compose的安装与卸载

    Docker以及Docker-Compose的安装与卸载 适合开发下运维人员学习

    尚硅谷宋红康C语言精讲.zip

    尚硅谷宋红康C语言精讲.zip

    matlab实现基于多源信息融合的水果虫灾智能检测系统研究-虫灾检测-智能检测系统-matlab-机器学习

    内容概要:本文提出了一种结合生物信息学、遥感技术和物联网技术的水果虫灾智能检测系统。通过收集和分析生物标志物、遥感影像和传感器数据,利用机器学习算法实现对虫灾的自动识别与预警,提高检测的准确性和时效性,为水果种植业的可持续发展提供支持。 适合人群:农业科学家、农艺师、农业技术开发人员。 使用场景及目标:适用于水果种植园的虫害监控,帮助农民及时发现和控制虫灾,减少农业生产损失。 其他说明:该系统不仅提高了虫灾检测的效率,还在一定程度上解决了传统方法耗时费力、准确性低的问题。系统未来将优化数据处理方法、提取更多有效特征,并尝试应用到其他农业领域。

    南平市2005-2024年近20年历史气象数据下载

    南平市2005-2024年近20年的历史气象数据,每3小时更新一次数据,参数包含气温、气压、降水量、云层、能见度、风向、湿度等,几万条数据

    数据结构上机实验大作业-线性表选题.zip

    数据结构上机实验大作业-线性表选题.zip

    弱电人需要的网络基础知识汇总.docx

    弱电人需要的网络基础知识汇总.docx

    生菜生长记录数据集(3K+ 记录,7特征) CSV

    本数据集记录了不同环境条件下植物生长数据信息。分析这些数据可以了解到,随着时间的推移,不同的温度、湿度、pH值和总溶解固体(TDS)等因素如何影响植物的生长发展。 数据说明: Plant_ID 每株植物的标识符 Date 观测日期 Temperature (°C) 温度,以摄氏度为单位 Humidity (%) 湿度水平,以百分比表示 TDS Value (ppm) 总溶解固体值,以百万分之一(ppm)为单位 pH Level 环境的pH值 Growth Days 植物从开始生长到完全长成所需的天数

    字幕网页文字检测20-YOLO(v5至v11)、COCO、CreateML、Paligemma、TFRecord、VOC数据集合集.rar

    字幕网页文字检测20-YOLO(v5至v11)、COCO、CreateML、Paligemma、TFRecord、VOC数据集合集.rarLLCMTVRC-V2 2024-05-04 11:24 PM ============================= *与您的团队在计算机视觉项目上合作 *收集和组织图像 *了解和搜索非结构化图像数据 *注释,创建数据集 *导出,训练和部署计算机视觉模型 *使用主动学习随着时间的推移改善数据集 对于最先进的计算机视觉培训笔记本,您可以与此数据集一起使用 该数据集包括161张图像。 随机文本以可可格式注释。 将以下预处理应用于每个图像: *像素数据的自动取向(带有Exif-Arientation剥离) *调整大小为640x640(拉伸) 应用以下扩展来创建每个源图像的3个版本: *随机裁剪图像的0%至30% * -16至+16度之间的随机旋转 将以下转换应用于每个图像的边界框: *水平的-3°至 +3°之间的随机剪切和-4°至 +4°垂直剪切

    冒泡排序算法解析及优化.md

    冒泡排序

    KeyboardInterrupt.md

    KeyboardInterrupt

    (2147634)经典C程序100例 很经典的例子

    C语言是一种强大的、通用的编程语言,被广泛用于系统编程、应用编程、嵌入式系统以及游戏开发等领域。它的简洁性和高效性使得它成为初学者和专业人士的首选语言。"经典C程序100例"这个资源是学习C语言的一个宝贵资料库,包含了多种常见问题的解决方案和编程技巧。 C语言的基础知识包括变量、数据类型、运算符、流程控制(如if语句、switch语句、循环结构for、while、do-while)以及函数的使用。这些基础知识在每个C程序中都不可或缺。例如,通过学习不同的数据类型(如int、char、float、double等),我们可以理解如何存储和处理不同类型的数据。而流程控制则帮助我们根据条件执行不同的代码段,实现逻辑判断和重复执行。 在C语言中,函数是代码组织的基本单元,可以实现代码复用和模块化。通过阅读和分析100个经典实例,我们可以看到如何定义和调用函数,以及如何传递参数和返回值。此外,指针是C语言的一大特色,它允许我们直接操作内存,提高程序的灵活性和效率。学习如何声明、初始化和使用指针是掌握C语言的关键。 结构体和联合体是C语言中复合数据类型,它们能将多个不同类型的数据组合成一个整体。在经

    时变动态分位数CoVaR、delta-CoVaR,分位数回归 △CoVaR测度 溢出效应 动态 Adrian2016基于分位数回归方法计算动态条件在险价值 R语言代码,代码更数据就能用,需要修改的

    时变动态分位数CoVaR、delta-CoVaR,分位数回归 △CoVaR测度 溢出效应 动态 Adrian2016基于分位数回归方法计算动态条件在险价值。 R语言代码,代码更数据就能用,需要修改的地方都已标明,并且举例怎么修改 每一行代码都有注释,一次可以计算出所有结果,不需要像Eviews一样两两重复计算。 例子为31家金融机构11-22年数据,包含4个宏观状态变量,计算结果见下图。

    基于Bmob校园签到系统全部资料+详细文档+高分项目.zip

    【资源说明】 基于Bmob校园签到系统全部资料+详细文档+高分项目.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

    python编译器Anaconda安装包下载(含各种版本)

    python编译器Anaconda安装包下载(含各种版本)

    冒泡排序算法详解及Java与Python实现

    内容概要:本文详细介绍了冒泡排序的基本原理及其实现方式,并提供了Java和Python两种语言的代码样例。首先解释了冒泡排序的工作机制,即通过重复遍历数组、比较相邻元素并在必要时进行交换来逐步将最大值移动到数组末尾,直至整个数组有序。文中给出的具体实现包括了标记法,可以在当前遍历过程中没有发生任何交换时提前终止排序过程,提高效率。此外,文中还提供了测试用的数据集及打印排序后的结果。 适合人群:适合计算机科学专业的初学者或者对基本排序算法有兴趣的技术人员。 使用场景及目标:可用于教学目的,帮助学生理解和掌握冒泡排序算法的原理及具体编程实现方法;同时,对于有经验的开发者来说,也是一个很好的复习材料。 阅读建议:建议读者跟随文章内容尝试动手实现相应的冒泡排序算法,并理解每一步操作的目的,以加深理解。

    计算机接口实验报告.zip

    计算机接口实验报告,环境:PC 机一台,TD-PITE 实验装置一套。报告内容有,实验目的、实验设备、实验内容、实验步骤、实验程序(汇编)、实验结果、实验总结,一步到位!!!!!! 一步到位!!!!!!

Global site tag (gtag.js) - Google Analytics