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

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事件(如可读、可写等)。`...

    YOLOv12:以注意力为中心的实时目标检测器.pdf

    YOLOv12:以注意力为中心的实时目标检测器

    GO语言基础语法指令教程

    GO语言基础语法指令教程

    MATLAB代码实现:分布式电源接入对配电网运行影响深度分析与评估,MATLAB代码分析:分布式电源接入对配电网运行影响评估,MATLAB代码:分布式电源接入对配电网影响分析 关键词:分布式电源 配电

    MATLAB代码实现:分布式电源接入对配电网运行影响深度分析与评估,MATLAB代码分析:分布式电源接入对配电网运行影响评估,MATLAB代码:分布式电源接入对配电网影响分析 关键词:分布式电源 配电网 评估 参考文档:《自写文档,联系我看》参考选址定容模型部分; 仿真平台:MATLAB 主要内容:代码主要做的是分布式电源接入场景下对配电网运行影响的分析,其中,可以自己设置分布式电源接入配电网的位置,接入配电网的有功功率以及无功功率的大小,通过牛顿拉夫逊法求解分布式电源接入后的电网潮流,从而评价分布式电源接入前后的电压、线路潮流等参数是否发生变化,评估配电网的运行方式。 代码非常精品,是研究含分布式电源接入的电网潮流计算的必备程序 ,分布式电源; 配电网; 接入影响分析; 潮流计算; 牛顿拉夫逊法; 电压评估; 必备程序。,基于MATLAB的分布式电源对配电网影响评估系统

    三相光伏并网逆变器:Mppt最大功率跟踪与800V中间母线电压的电力转换技术,三相光伏并网逆变器:实现最大功率跟踪与800V中间母线电压的优化处理,三相光伏并网逆变器 输入光伏Mppt 最大功率跟踪

    三相光伏并网逆变器:Mppt最大功率跟踪与800V中间母线电压的电力转换技术,三相光伏并网逆变器:实现最大功率跟踪与800V中间母线电压的优化处理,三相光伏并网逆变器 输入光伏Mppt 最大功率跟踪中间母线电压800V 后级三相光伏并网逆变器 ,三相光伏并网逆变器; 输入光伏Mppt; 最大功率跟踪; 中间母线电压800V; 后级逆变器,三相光伏并网逆变器:MPPT最大功率跟踪800V母线电压

    基于SSM的车位销售平台设计与实现.zip(毕设&课设&实训&大作业&竞赛&项目)

    项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行,功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用

    西门子博途三部十层电梯程序案例解析:基于Wincc RT Professional V14及更高版本的应用探索,西门子博途三部十层电梯程序案例解析:基于Wincc RT Professional画面与

    西门子博途三部十层电梯程序案例解析:基于Wincc RT Professional V14及更高版本的应用探索,西门子博途三部十层电梯程序案例解析:基于Wincc RT Professional画面与V14及以上版本技术参考,西门子1200博途三部十层电梯程序案例,加Wincc RT Professional画面三部十层电梯程序,版本V14及以上。 程序仅限于参考资料使用。 ,西门子;1200博途;三部十层电梯程序案例;Wincc RT Professional;V14以上程序版本。,西门子V14+博途三部十层电梯程序案例:Wincc RT Pro专业画面技术解析

    基于舆情数据的知识图谱推荐可视化系统论文,全原创,免费分享

    基于舆情数据的知识图谱推荐可视化系统论文,全原创,免费分享

    基于Vivado源码的AM包络检调制解调与FIR滤波器设计在FPGA上的实现,基于Zynq-7000和Artix-7系列的AM包络检调制解调源码及Vivado环境下的实现,AM包络检调制解调,Viva

    基于Vivado源码的AM包络检调制解调与FIR滤波器设计在FPGA上的实现,基于Zynq-7000和Artix-7系列的AM包络检调制解调源码及Vivado环境下的实现,AM包络检调制解调,Vivado源码 FPGA的AM调制解调源码,其中FIR滤波器根据MATLAB设计。 【AM_jietiao】文件是基于zynq-7000系列,但没有涉及AD与DA,只是单纯的仿真。 【AM包络检调制解调_Vivado源码】文件基于Artix-7系列,从AD读入信号后,进行AM调制,并解调DA输出。 ,AM包络检调制解调;Vivado源码;FPGA;AM调制解调源码;FIR滤波器;MATLAB设计;Zynq-7000系列;Artix-7系列;AD读入信号;DA输出,AM包络调制解调源码:Zynq-7000与Artix-7 FPGA的不同实现

    rdtyfv、ijij

    yugy

    2025山东大学:DeepSeek应用与部署(部署方案大全+API调用+业务应用)-80页.pptx

    2025山东大学:DeepSeek应用与部署(部署方案大全+API调用+业务应用)-80页.pptx

    chromedriver-mac-x64-135.0.7023.0(Dev).zip

    chromedriver-mac-x64-135.0.7023.0(Dev).zip

    基于单片机protues仿真的433MHz无线模块编解码收发通信测试(仿真图、源代码)

    基于单片机protues仿真的433MHz无线模块编解码收发通信测试(仿真图、源代码) 该设计为单片机protues仿真的433MHz无线模块收发通信测试; 1、433M超再生收发模块; 2、在仿真图中是把发射MCU的P2_7腿直接输入到接收MCU的INT0实现编码解码的; 3、通过433MHz无线模块实现无线通信的编解码功能; 4、按键控制指令; 5、液晶屏显示收发状态和信息;

    车机安卓版好用的应用管理app

    资源说说明; 自带文件管理 adb操作以及应用管理等等的功能。 操作性对比其他应用较好。 参阅博文: https://blog.csdn.net/mg668/article/details/145689511?spm=1001.2014.3001.5352

    软件工程课程设计前端.zip

    项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行,功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用

    智慧图书管理系统(源码+数据库+论文)java开发springboot框架javaweb,可做计算机毕业设计或课程设计

    智慧图书管理系统(源码+数据库+论文)java开发springboot框架javaweb,可做计算机毕业设计或课程设计 【功能需求】 本系统分为读者、管理员2个角色 读者可以进行注册登录、浏览图书以及留言、图书借阅、图书归还、图书续借、个人中心、论坛交流、等功能 管理员可以进行读者管理、图书管理、论坛论坛回复管理、图书借阅管理(下架、库存管理、修改、删除)、轮播图管理 【环境需要】 1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境:IDEA,Eclipse,Myeclipse都可以。 3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可 4.数据库:MySql 5.7/8.0等版本均可; 【购买须知】 本源码项目经过严格的调试,项目已确保无误,可直接用于课程实训或毕业设计提交。里面都有配套的运行环境软件,讲解视频,部署视频教程,一应俱全,可以自己按照教程导入运行。附有论文参考,使学习者能够快速掌握系统设计和实现的核心技术。

    三相APFC电路与单相Boost PFC电路仿真模型:电压外环电流内环双闭环控制研究,三相电路仿真模型:探索APFC电路、单相PFC电路及BoostPFC电路的动态特性与双闭环控制策略,APFC电路

    三相APFC电路与单相Boost PFC电路仿真模型:电压外环电流内环双闭环控制研究,三相电路仿真模型:探索APFC电路、单相PFC电路及BoostPFC电路的动态特性与双闭环控制策略,APFC电路,单相PFC电路,单相BoostPFC电路仿真模型。 网侧220V 50Hz,输出电压设置为50Hz。 电压外环电流内环双闭环控制仿真模型 ,APFC电路; 单相PFC电路; 单相BoostPFC电路仿真模型; 网侧电压; 220V 50Hz; 输出电压50Hz; 电压外环电流内环双闭环控制仿真模型。,基于APFC电路的单相Boost PFC仿真模型:网侧电压220V/50Hz下电压电流双闭环控制的研究与应用

    MATLAB环境下ADMM算法在分布式调度中的应用:比较并行与串行算法(Jocobi与Gaussian Seidel)的优化效果与实现细节-基于YALMIP和GUROBI的仿真平台复刻参考文档的研究

    MATLAB环境下ADMM算法在分布式调度中的应用:比较并行与串行算法(Jocobi与Gaussian Seidel)的优化效果与实现细节——基于YALMIP和GUROBI的仿真平台复刻参考文档的研究结果。,MATLAB下ADMM算法在分布式调度中的并行与串行算法应用:基于YALMIP与GUROBI的仿真研究,MATLAB代码:ADMM算法在分布式调度中的应用 关键词:并行算法(Jocobi)和串行算法(Gaussian Seidel, GS) 参考文档:《主动配电网分布式无功优化控制方法》《基于串行和并行ADMM算法的电-气能量流分布式协同优化》 仿真平台:MATLAB YALMIP GUROBI 主要内容:ADMM算法在分布式调度中的应用 复刻参考文档 ,关键词:ADMM算法; 分布式调度; 并行算法(Jocobi); 串行算法(Gaussian Seidel, GS); MATLAB代码; YALMIP; GUROBI; 主动配电网; 无功优化控制方法; 能量流分布式协同优化。,MATLAB实现:ADMM算法在分布式调度中的并行与串行优化应用

    “考虑P2G、碳捕集与碳交易机制的综合能源系统优化调度模型研究”,考虑电转气P2G与碳捕集设备的热电联供综合能源系统优化调度模型研究(含碳交易机制与四种算例场景分析),考虑P2G和碳捕集设备的热电联供

    “考虑P2G、碳捕集与碳交易机制的综合能源系统优化调度模型研究”,考虑电转气P2G与碳捕集设备的热电联供综合能源系统优化调度模型研究(含碳交易机制与四种算例场景分析),考虑P2G和碳捕集设备的热电联供综合能源系统优化调度模型 摘要:代码主要做的是一个考虑电转气P2G和碳捕集设备的热电联供综合能源系统优化调度模型,模型耦合CHP热电联产单元、电转气单元以及碳捕集单元,并重点考虑了碳交易机制,建立了综合能源系统运行优化模型,与目前市面上的代码不同,本代码完全复现了文档中所提出的四种算例场景,没有对比算例,买过去也没有任何意义,四种算例主要包括: 1)t不包括P2G、CCS、以及碳交易 2)t包括P2G,但是不包括CCS以及碳交易 3)t包括P2G和CCS,但是不包括碳交易 4)t包括P2G、CCS以及碳交易 且最终的实现效果与文档进行对比后,虽然数值无法100%一致,但是结果以及数值曲线,几乎完全一样,此版本为目前市面上最好的园区综合能源调度代码,没有之一 ,考虑电转气(P2G); 碳捕集设备; 热电联供综合能源系统; 优化调度模型; 碳交易机制; CHP热电联产单元; 耦合模型; 算

Global site tag (gtag.js) - Google Analytics