新手想做网站赚钱网站设计与制作报价

web/2025/10/5 8:48:07/文章来源:
新手想做网站赚钱,网站设计与制作报价,ueditor上传wordpress,如何做充值网站基本介绍 栈内存一般是由Go编译器自动分配和释放#xff0c;其中存储着函数的入参和局部变量#xff0c;这些参数和变量随着函数调用而创建#xff0c;当调用结束后也会随之被回收。通常开发者不需要关注内存是分配在堆上还是栈上#xff0c;这部分由编译器在编译阶段通过…基本介绍 栈内存一般是由Go编译器自动分配和释放其中存储着函数的入参和局部变量这些参数和变量随着函数调用而创建当调用结束后也会随之被回收。通常开发者不需要关注内存是分配在堆上还是栈上这部分由编译器在编译阶段通过逃逸分析来决定。但是了解其原理还是很重要的。一方面可以帮助我们有意识写出更高效的可执行代码另一方面参考源码中的一些精妙设计也可以给自己一定的思路。 设计原理 寄存器 寄存器是CPU中的稀缺资源他的存储能力非常有限但是能提供最快的读写速度充分利用寄存器的读写速度可以构建高性能的应用程序。寄存器在物理机上非常有限然后Go的栈操作仍然用了两个以上寄存器充分说明栈内存的重要性。 栈寄存器是CPU寄存器的一种用于跟踪函数的调用栈。Go语言的汇编代码包括了BP和SP两个寄存器他们分别存储了栈的基址指针和栈顶指针BP和SP之间的部分就是函数的调用栈。 堆的内存增长是从小往大增长而栈的增长方向是相反的导致在做栈指令操作的时候将 SP 减小反而是将栈帧增大。这样做的好处就是便于堆和栈可动态共享那段内存区域。 当应用程序申请或者释放栈内存时只需要修改 SP 寄存器的值这种线性的内存分配方式与堆内存相比更加快速仅会带来极少的额外开销。 在函数执行过程中CPU会通过栈寄存器来来访问和操作栈内存当函数被调用时CPU会将函数的入参和返回值地址压入栈中并将SP指向新的栈顶。在函数内部CPU可以通过BP来来访问栈中的参数和局部变量当函数返回后CPU会将栈顶元素弹出栈将SP指针恢复到函数调用前的状态。 栈寄存器和栈内存密切相关栈寄存器用于管理栈内存的指针栈内存则用于存储函数调用时的参数和局部变量。 // (x86)系统下栈帧布局 // ------------------ // | args from caller | // ------------------ - frame-argp // | return address | // ------------------ // | callers BP (*) | (*) if framepointer_enabled varp sp // ------------------ - frame-varp // | locals | // ------------------ // | args to callee | // ------------------ - frame-sp栈操作 栈初始化 // linux上_NumStackOrders4表示四种大小的栈分别是2kb、4kb、8kb、16kb var stackpool [_NumStackOrders]struct {item stackpoolItem// 内存对齐_ [cpu.CacheLinePadSize - unsafe.Sizeof(stackpoolItem{})%cpu.CacheLinePadSize]byte }func stackinit() {if _StackCacheSize_PageMask ! 0 {throw(cache size must be a multiple of page size)}for i : range stackpool {stackpool[i].item.span.init()lockInit(stackpool[i].item.mu, lockRankStackpool)}for i : range stackLarge.free {stackLarge.free[i].init()lockInit(stackLarge.lock, lockRankStackLarge)} }可以看到栈初始化过程中有两个关键变量stackpool和stackLarge其中stackpool是全局的栈缓存用来分配小于32k的内存stackLarge是大栈缓存用来分配大于32k的内存此处可见栈分配部分代码这两部分的内存都是从全局的heap_中申请所以也可以认为Go中的栈内存也是分配在堆上的。 如果仅仅用这两个全局变量来分配栈内存那么可预见的是在程序运行期间申请和释放栈空间必然需要频繁加锁会影响程序执行效率所以Go在mcache线程缓存级别增加了一级栈缓存在创建goroutine的时候会给自己分配一个栈空间详见malg()大部分情况下每个goroutine只需要在自己的栈空间申请内存即可不需要再竞争锁。具体结构可见。mache中的栈缓存并非单独从mheap中申请 stackinit函数在schedinit中调用 func schedinit() {...stackinit()... }运行时使用全局的 runtime.stackpool 和线程缓存中的空闲链表分配 32KB 以下的栈内存使用全局的 runtime.stackLarge 和堆内存分配 32KB 以上的栈内存提高本地分配栈内存的性能。 栈分配 运行会在创建goroutine的时候调用runtime.stackalloc来预先分配一个大小足够的内存空间。 // Allocate a new g, with a stack big enough for stacksize bytes. // newproc()调用newproc1()newproc1()调用malg()在调用malg的时候会传入_StackMin 2048即最小栈2k func malg(stacksize int32) *g {newg : new(g)if stacksize 0 {// 这里会在 stacksize 的基础上为每个栈预留系统调用所需的内存大小 // _StackSystem在 Linux/Darwin 上 _StackSystem 0 本行不改变 stacksize 的大小stacksize round2(_StackSystem stacksize)systemstack(func() {// 为新分配的G对象分配栈内存newg.stack stackalloc(uint32(stacksize))})newg.stackguard0 newg.stack.lo _StackGuardnewg.stackguard1 ^uintptr(0)// Clear the bottom word of the stack. We record g// there on gsignal stack during VDSO on ARM and ARM64.*(*uintptr)(unsafe.Pointer(newg.stack.lo)) 0}return newg }_StackGuard在linux上默认大小是928个字节所以初始化分配的2kb栈内存只有1120个字节可用所以在实际使用中如果栈的长度达到1120那么就会触发栈扩容。 stackalloc会根据分配栈内存的大小分别用不同的方案分配栈内存 如果申请的栈内存32k会从全局栈缓存stackpool或线程缓存的栈上分配否则会直接从大栈stackLarge分配 func stackalloc(n uint32) stack {thisg : getg()...// 在linux上_FixedStack2048_NumStackOrders4_StackCacheSize32 * 1024// 如果申请的栈内存32k则通过stackpool或mcache上的缓存栈分配if n _FixedStack_NumStackOrders n _StackCacheSize {order : uint8(0)n2 : n// 一直除到n2048order记录除了几次// order0表示2kborder1表示4kb以此类推for n2 _FixedStack {ordern2 1}// stackNoCache表示是否禁止线程缓存上的栈常量默认值是0// thisg.m.p 0会在系统调用和改变P的个数的时候调用满足条件就从stackpool上分配// preemptoff ! , 在 GC 的时候会进行设置,表示如果在 GC 那么从 stackpool 分配if stackNoCache ! 0 || thisg.m.p 0 || thisg.m.preemptoff ! {lock(stackpool[order].item.mu)// 从stackpool中分配对应大小的栈如果stackpool空间不足会从堆上申请x stackpoolalloc(order)unlock(stackpool[order].item.mu)} else {// 获取执行g的P上的mcachec : thisg.m.p.ptr().mcache// 在线程缓存上获取预分配大小的栈x c.stackcache[order].listif x.ptr() nil {// 从堆上申请新的内存填充到线程缓存中stackcacherefill(c, order)x c.stackcache[order].list}// 移除空闲栈链表上的第一个节点表示已分配c.stackcache[order].list x.ptr().next// 更新分配栈后的空闲栈大小c.stackcache[order].size - uintptr(n)}// 如果32k则通过stackLarge分配} else {var s *mspannpage : uintptr(n) _PageShiftlog2npage : stacklog2(npage)// Try to get a stack from the large stack cache.lock(stackLarge.lock)// 如果有空闲的栈内存直接从stackLarge中分配if !stackLarge.free[log2npage].isEmpty() {s stackLarge.free[log2npage].firststackLarge.free[log2npage].remove(s)}unlock(stackLarge.lock)// 如果没有空闲的栈则直接从堆上申请新的if s nil {// Allocate a new stack from the heap.s mheap_.allocManual(npage, spanAllocStack)if s nil {throw(out of memory)}osStackAlloc(s)s.elemsize uintptr(n)}} }需要注意的是因为 OpenBSD 6.4 对栈内存有特殊的需求所以只要我们从堆上申请栈内存需要调用 runtime.osStackAlloc 做一些额外处理然而其他的操作系统就没有这种限制了。 stackalloc中有两个重要的函数调用再展开看看 // 从stackpool中分配栈 func stackpoolalloc(order uint8) gclinkptr {// 获取对应大小的栈链表并拿到第一个节点list : stackpool[order].item.spans : list.firstif s nil {// 如果没有空闲的栈则从堆中申请新的mspans mheap_.allocManual(_StackCacheSize_PageShift, spanAllocStack)...osStackAlloc(s)s.elemsize _FixedStack order// 新申请的栈内存写入manualFreeListmanualFreeList是一个单向链表for i : uintptr(0); i _StackCacheSize; i s.elemsize {x : gclinkptr(s.base() i)x.ptr().next s.manualFreeLists.manualFreeList x}// 插入stackpoollist.insert(s)}// 从mspan获取object可见mspan的定义mspan是一串连续page然后按照size_class分割成固定大小的objectmanualFreeList用来维护栈内存x : s.manualFreeListif x.ptr() nil {throw(span has no free stacks)}// 从manualFreeList上删除第一个节点s.manualFreeList x.ptr().next// mspan分配对象1s.allocCount// 如果分配完mspan中栈对象已分配完从stackpool中删除该mspanif s.manualFreeList.ptr() nil {// all stacks in s are allocated.list.remove(s)}return x } // 填充mcache中的栈缓存 func stackcacherefill(c *mcache, order uint8) {if stackDebug 1 {print(stackcacherefill order, order, \n)}// Grab some stacks from the global cache.// Grab half of the allowed capacity (to prevent thrashing).var list gclinkptrvar size uintptrlock(stackpool[order].item.mu)// _StackCacheSize32k此处先从stackpool中获取一半即16k大小组成单向链表放到mcache中// 猜测这里的一半是和空间利用率有关直接分配全部32k可能会造成浪费如果当前栈内存使用率不足1/4那么也会触发缩容每次缩1/2for size _StackCacheSize/2 {x : stackpoolalloc(order)x.ptr().next listlist x// _FixedStack2048size _FixedStack order}unlock(stackpool[order].item.mu)// 放入mcache中c.stackcache[order].list listc.stackcache[order].size size }栈分配时的order和堆分配的sizeclass有异曲同工之妙一方面可以减少不同goroutine获取不同大小栈的锁冲突另一方面可以预先缓存对应大小的内存以便快速获取。在Go的内存分配中有很多类似的思路通过预分配分级等减少锁冲突提高内存分配效率 栈扩容 编译器会在 cmd/internal/obj/x86.stacksplit 中为函数调用插入 runtime.morestack 运行时检查它会在几乎所有的函数调用之前检查当前 Goroutine 的栈内存是否充足如果当前栈需要扩容我们会保存一些栈的相关信息并调用 runtime.newstack 创建新的栈 func newstack() {thisg : getg()... // 校验逻辑gp : thisg.m.curg...morebuf : thisg.m.morebuf// 初始化寄存器相关变量thisg.m.morebuf.pc 0thisg.m.morebuf.lr 0thisg.m.morebuf.sp 0thisg.m.morebuf.g 0// 校验是否被抢占preempt : stackguard0 stackPreemptif preempt {// 校验M是否可以被安全抢占如果不可以安全抢占那么就不执行抢占让当前goroutine继续执行等下次再抢占// canPreemptMreturn mp.locks 0 mp.mallocing 0 mp.preemptoff mp.p.ptr().status _Prunning// 如果M上没有锁或没有在进行内存分配或没有禁止抢占或P的状态是Running认为可以安全抢占if !canPreemptM(thisg.m) {// Let the goroutine keep running for now.// gp-preempt is set, so it will be preempted next time.gp.stackguard0 gp.stack.lo _StackGuard// 触发调度器调度gogo(gp.sched) // never return}}// 如果被抢占且可以安全抢占说明当前goroutine不需要执行也不需要栈扩容if preempt {// 需要收缩栈if gp.preemptShrink {// Were at a synchronous safe point now, so// do the pending stack shrink.gp.preemptShrink falseshrinkstack(gp)}// 被runtime.suspendG挂起后被动让出当前处理器的控制权if gp.preemptStop {preemptPark(gp) // never returns}// 主动让出当前处理器的控制权gopreempt_m(gp) // never return}// 到此处如果当前goroutine不需要被抢占那么就说明需要新的栈内存来执行代码和初始化变量此时继续往下执行进行扩容oldsize : gp.stack.hi - gp.stack.lo// 新栈空间按照原来的2倍扩容newsize : oldsize * 2// 如果仍然不够用则继续按照2倍扩容if f : findfunc(gp.sched.pc); f.valid() {max : uintptr(funcMaxSPDelta(f))needed : max _StackGuardused : gp.stack.hi - gp.sched.spfor newsize-used needed {newsize * 2}}...// 栈溢出检测// maxstacksize 64位是1Gmaxstackceiling2*maxstacksize// maxstackceiling 用来兜底防止用户调用runtime.setMaxStack()把maxstacksize设置得过大if newsize maxstacksize || newsize maxstackceiling {...}// 状态置为_Gcopystackcasgstatus(gp, _Grunning, _Gcopystack)// The concurrent GC will not scan the stack while we are doing the copy since// the gp is in a Gcopystack status.// 扩容并拷贝copystack(gp, newsize)if stackDebug 1 {print(stack grow done\n)}// 状态置为_Grunningcasgstatus(gp, _Gcopystack, _Grunning)// 触发调度器调度gogo(gp.sched) }newstack主要流程 校验是否可以被安全抢占如果可以被安全抢占就直接调用runtime.gogo触发调度器的调度如果GC的时候被runtime.scanstack 标记了需要收缩栈则调用shrinkstack()缩容并把preemptShrink状态标记为false等待下次GC扫描如果GC的时候当前goroutine被runtime.suspendG挂起则被动让出当前处理器的控制权并把状态置为_Gpreempted之后会在下一次调用runtime.suspendG的时候把状态改回到_GWaiting调用gopreempt_m主动让出当前处理器的控制权 如果当前gorouine不需要被抢占那么就说明需要扩容新的栈空间来执行函数代码和变量初始化 接下来再看copystack调用该函数之前需要先把g的状态置为Gcopystack func copystack(gp *g, newsize uintptr) {old : gp.stack...// 旧栈高位指针-G对象栈顶指针计算当前已使用栈内存大小参考上面寄存器和栈帧布局理解used : old.hi - gp.sched.sp// 分配新的栈空间new : stackalloc(uint32(newsize))// 借助adjustinfo来调整栈空间var adjinfo adjustinfo// 存放旧栈adjinfo.old old// 新旧栈的调整距离用该值控制指针移动距离adjinfo.delta new.hi - old.hi// sudog represents a g in a wait list, such as for sending/receiving on a channel.ncopy : usedif !gp.activeStackChans {adjustsudogs(gp, adjinfo)} else {// 到这里代表有被阻塞的 G 在当前 G 的channel 中所以要防止并发操作需要获取 channel 的锁// 在所有 sudog 中找到地址最大的指针adjinfo.sghi findsghi(gp, old)// 对所有 sudog 关联的 channel 上锁然后调整指针并且复制 sudog 指向的部分旧栈的数据到新的栈上ncopy - syncadjustsudogs(gp, used, adjinfo)}// 将旧栈中的数据整片拷贝到新栈中memmove(unsafe.Pointer(new.hi-ncopy), unsafe.Pointer(old.hi-ncopy), ncopy)// 调整ctxtdefer和panic的指针// 调用 runtime.adjustpointer该函数会利用 runtime.adjustinfo 计算的新栈和旧栈之间的内存地址差来调整指针adjustctxt(gp, adjinfo)adjustdefers(gp, adjinfo)adjustpanics(gp, adjinfo)// 把G上的栈替换为新栈gp.stack newgp.stackguard0 new.lo _StackGuard // NOTE: might clobber a preempt requestgp.sched.sp new.hi - usedgp.stktopsp adjinfo.delta// 调整新栈上的指针gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, adjustframe, noescape(unsafe.Pointer(adjinfo)), 0)// 释放旧栈空间stackfree(old) }总结一下栈扩容的步骤 前置校验如果当前goroutine可以被抢占那么就停止栈扩容按照最小两倍来重新计算需要的栈内存暂停当前goroutine的执行新建一个栈空间并迁移数据复制旧栈数据到新栈更改指向旧栈空间的指针指向新栈空间触发系统调度恢复当前goroutine的执行 栈缩容 栈的缩容发生在GC扫描阶段在scanstack函数内触发缩容 func scanstack(gp *g, gcw *gcWork) int64 {// 当我们拥有所有栈帧的精确指针映射时认为是此时收缩栈是安全的if isShrinkStackSafe(gp) {// 直接缩容shrinkstack(gp)} else {// 在newobject中执行缩容gp.preemptShrink true} }接下来看具体是怎么缩容的 func shrinkstack(gp *g) {... // 校验逻辑oldsize : gp.stack.hi - gp.stack.lo// 缩容到原来的一半newsize : oldsize / 2// 如果缩容的大小小于栈的最小值2KB就停止if newsize _FixedStack {return}avail : gp.stack.hi - gp.stack.lo// 如果已使用内存超过可用空间的1/4也停止缩容if used : gp.stack.hi - gp.sched.sp _StackLimit; used avail/4 {return}// 调用copystack开辟新的栈并复制数据copystack(gp, newsize) }逃逸分析 代码中如果某个对象被分配到堆上那么就称该对象发生了内存逃逸 在编译器优化中逃逸分析是用来决定指针动态作用域的方法。Go 语言的编译器使用逃逸分析决定哪些变量应该在栈上分配哪些变量应该在堆上分配其中包括使用 new、make 和字面量等方法隐式分配的内存Go 语言的逃逸分析遵循以下两个不变性/src/cmd/compile/internal/gc/escape.go 指向栈对象的指针不能存在于堆中pointers to stack objects cannot be stored in the heap指向栈对象的指针不能在栈对象回收后存活pointers to a stack object cannot outlive that object 如果违反第一条原则函数调用结束后函数内分配的局部变量会被回收那么绿色指针指向的指将不合法如果违反第二条原则函数调用结束后粉色部分内存被回收如果指向栈对象的指针仍然存活那么黄色指针指向的值也将不合法 内存逃逸的影响 如果频繁发生内存逃逸本可以分配在栈上的变量分配在了堆上就会存在下面问题 内存占用增加由于Go的内存分配策略堆扩容后并不会马上把内存归还给系统所以会导致Go程序持有的内存不断增长对于长时间不更新的系统来说内存必然会持续增长进而触发资源报警GC压力增加分配到堆上的对象不会随着函数调用结束而释放而会等待GC标记、扫描等步骤后才回收会导致垃圾回收器频繁操作影响服务稳定性性能下降堆内存分配比栈内存分配需要更多的CPU和内存资源会导致程序性能变差 内存逃逸的原因及优化思路 以下是一些内存逃逸的case 变量的生命周期超出了其作用域当一个变量在函数外部被引用比如被赋值给一个包级别的变量或者作为返回值这个变量就会发生逃逸。 要严格限制作用域仅在函数内部使用的变量不要返回给外部使用值而不是指针传值会拷贝整个对象传指针只需要拷贝指针地址但会增加GC压力因此需要平衡考虑对于小对象推荐使用值传递参考benchmark28B是分界线供参考 大对象的分配对于大型的数据结构Go 有时会选择在堆上分配内存即使它们没有在函数外部被引用。 对于频繁创建和销毁的对象可以池化减少在堆上分配和GC的次数 闭包引用如果一个函数返回一个闭包并且该闭包引用了函数的局部变量那么这些变量也会逃逸到堆上。 应当尽量避免在大循环或频繁调用的函数中使用闭包 接口动态分配当一个具体类型的变量被赋值给接口类型时由于接口的动态特性具体的值可能会发生逃逸。 对于频繁创建的对象应当尽量使用确定的类型 切片和 map 操作如果对切片进行操作可能导致其重新分配内存或者向 map 中插入数据这些操作可能导致逃逸。 对于切片如果是确定的长度推荐使用数组如果可以确定大小在对象初始化的时候就分配好容量避免在运行期间频繁扩容 参考 https://www.luozhiyun.com/archives/513 https://draveness.me/golang/docs/part3-runtime/ch07-memory/golang-stack-management/ https://zhuanlan.zhihu.com/p/386769009?utm_id0 https://zhuanlan.zhihu.com/p/672733054

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/87273.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国际贸易英文网站标志设计课件

继续上一章部署。 八、部署kube-apiserver组件 使用第七章的haproxy和keepalived部署的高可用集群提供的VIP:${MASTER_VIP} 8.1 下载二进制文件,参考 第三章  8.2 创建 kubernetes 证书和私钥 source /opt/k8s/bin/environment.sh cat > kubernetes-…

一个网站两个空间2023免费推广网站

GPADC 模块介绍 GPADC 是 12bit 采集精度的模数转换模块,支持 4 路通道,模拟输入范围 0-1.8v,最高采样率 1MHZ,并且支持数据比较,自校验功能,同时工作于可配置的四种工作模式: Single mode&a…

建设物流网站个人网站备案网址导航

​ 什么是代码混淆? 代码混淆 是一种将应用程序二进制文件转换为功能上等价,但人类难于阅读和理解的行为。在编译 Dart 代码时,混淆会隐藏函数和类的名称,并用其他符号替代每个符号,从而使攻击者难以进行逆向工程。 …

html5自适应网站源码wordpress小清新主题图片

1、配置工具 虽然不怎么好用,但比没有强多了。具体看图: 时钟选着 NVIC配置 GPIO配置 2、生成的具体配置信息 NXP的配置工具里面,具体的波特率可以直接显示,这个工具没有,怎么办? 它放到了生成的代码里面…

微网站策划方案互联网公司岗位有哪些

在很多产品的应用场景中,WIFI网络会给我们提供很多便捷,MCU开发中大多使用串口WIFI蓝牙模块来实现产品接入WIFI网络中。   具体的使用模型如下图所示:整个系统涉及到WIFI网络、手机、服务器平台以及我们设计的产品,一个完整的生…

信息平台网站的建设 文档怎么申请微信公众号

因为之前网上查好多博客都是只说最基础的,所以这里记录一下,最基础的放在最后面。 这里重点要记录的是枚举成员的值可以是字符串(字符串枚举,因为网上大部分只介绍常数枚举),需要注意的一点是,…

怎么提交网站收录如何做机票预订网站

在现代企业的运营管理中,泳道图扮演了至关重要的角色。这种独特的图表工具以其直观、清晰的特点,帮助我们理解和改进复杂的工作流程,从而提升效率。本文将为你分享8款实用且高效的泳道图绘制工具,它们能够帮助你轻松创建出专业级别…

网站建设什么意思手游代理免费平台

相对于 su 需要了解新切换的使用者密码 (常常是需要 root 的密码), sudo 的执行则仅需要自己的密码即可。sudo 可以让你以其他用户的身份执行指令 (通常是使用 root 的身份来执行指令),因此并非所有人都能够…

网站上线过程做网站多钱一年

1.新学到一个东西&#xff0c;将字符串转换为数字的函数stoi&#xff08;string to int 的缩写&#xff09; string str "111111";int a stoi(str);cout << a << endl;//输出111111又用到了字符串截取函数 substr(下标&#xff0c;长度) string s&quo…

2022年中国企业500强名单河南纯手工seo

什么是 CSS? CSS 指层叠样式表 (Cascading Style Sheets)样式定义如何显示 HTML 元素样式通常存储在样式表中把样式添加到 HTML 4.0 中&#xff0c;是为了解决内容与表现分离的问题外部样式表可以极大提高工作效率外部样式表通常存储在 CSS 文件中多个样式定义可层叠为一个 样…

网站推广渠道有哪些自适应h5网站模板

AI绘画工具为设计师提供了强大的功能和便利性&#xff0c;用AI绘画进行艺术创作能够使设计师能够更快地迭代和优化设计方案&#xff0c;提高设计效率。那么怎么用AI绘画完成设计创作? 要使用AI绘画完成设计创作&#xff0c;首先需要选择一个合适的工具。目前市场上有很多优秀的…

对网站有效的优化软件手机网站开发软件

大家好&#xff0c;Python是一种非常流行的编程语言&#xff0c;它易于学习、灵活且功能强大&#xff0c;在各个领域广泛应用。很多人误认为Python是一种面向过程的语言&#xff0c;无法很好地支持面向对象的编程风格。这种观念是错误的&#xff0c;Python不仅支持面向对象编程…

网站收录是什么意思网站建设风景课程设计报告

408答疑 文章目录 一、图的基本概念图的定义非空性非线性结构 顶点和边的表示顶点边 有向图 & 无向图有向图有向图 G 1 G_1 G1​ 的表示 无向图无向图 G 2 G_2 G2​ 的表示 简单图 & 多重图简单图多重图 顶点的度、入度和出度顶点的度有向图的度 路径、路径长度和回路…

网站企业优化wordpress多级分类文章

最近使用一个系统的分布式版本搭建测试环境&#xff0c;该系统是基于MPI实现的并行计算&#xff0c;MPI是传统基于msg的系统&#xff0c;这个框架非常灵活&#xff0c;对程序的结构没有太多约束&#xff0c;高效实用简单&#xff0c;下面是MPI在多台机器上实现并行计算的过程。…

怎样申请网站域名装修高端网站建设

在Vue.js&#xff08;以及更广泛的JavaScript ES6模块系统中&#xff09;中&#xff0c;使用大括号{}进行import操作的场景通常是在你想要从模块中导入具体的导出项时。这种导入方式被称为“命名导入”&#xff08;Named Imports&#xff09;。 命名导入&#xff08;Named Imp…

网页设计什么专业能学宁波外贸网站推广优化

1 介绍 MongoDB 是一种 NoSQL 数据库&#xff0c;它将每个数据存储为一个文档&#xff0c;这里的文档类似于 JSON/BSON 对象&#xff0c;具体数据结构由键值&#xff08;key/value&#xff09;对组成。字段值可以包含其他文档&#xff0c;数组及文档数组。其数据结构非常松散&…

做的asp网站手机号码酷站是什么网站

一、引言 一个算法是由控制结构&#xff08;顺序、分支和循环3种&#xff09;和原操作&#xff08;指固有数据类型的操作&#xff09;构成的&#xff0c;则算法时间取决于两者的综合效果。为了便于比较同一问题的不同算法&#xff0c;通常的做法是&#xff1a;从算法中选取一种…

网络推广的途径有哪些湖南正规seo优化报价

一 为什么要优化标题&#xff1f; 标题是爆单的核心因素 有搜索的地方就有关键词检索 抖音现在重点扶持搜索板块 关键词检索不仅为了 消费者、也为了 达人。 二 关键词的组成和原则 1 核心词 n. &#xff08;你卖的东西&#xff09; 示例&#xff1a;连衣裙 2 属性词 …

手表网站欧米茄报价wordpress爬虫ca

2016年五一杯数学建模 B题 能源总量控制下的城市工业企业协调发展问题 原题再现 能源是国民经济的重要物质基础,是工业企业发展的动力&#xff0c;但是过度的能源消耗&#xff0c;会破坏资源和环境&#xff0c;不利于经济的可持续发展。目前我国正处于经济转型的关键时期&…

烟台开发区网站建设个人网站备案 照片

文章目录 openpnp - SlotSchultzFeeder source code bugfix概述笔记openpnp源码调试环境排查思路开git分支查到的问题 - 1查到的问题 - 2查到的问题 - 3针对以上问题进行的逻辑修正D:\my_openpnp\openpnp_github\src\main\java\org\openpnp\machine\reference\driver\wizards\G…