• 关于

    Block_基本使用

    的搜索结果

回答

Flask-Admin Github存储库中有一个自定义布局的示例,即“自定义布局”。 在您的特定情况下,您需要删除` 基本布局模板文件的{{%block page_body%}`Jinja2块中的html部分。 在项目的templates / admin目录中创建一个menuless-layout.html文件,该文件扩展了内置的基本布局。复制并粘贴{%block page_body%} {%endblock%}块并删除` `部分。 {% import 'admin/layout.html' as layout with context -%} {% extends 'admin/base.html' %} {% block page_body %} <div class="container{%if config.get('FLASK_ADMIN_FLUID_LAYOUT', False) %}-fluid{% endif %}"> <!-- Nav section removed --> {% block messages %} {{ layout.messages() }} {% endblock %} {# store the jinja2 context for form_rules rendering logic #} {% set render_ctx = h.resolve_ctx() %} {% block body %}{% endblock %} </div> {% endblock %} 然后指示Flask-Admin使用此模板作为基本布局: # Create admin with custom base template admin = admin.Admin(app, 'Example', base_template='admin/menuless-layout.html', template_mode='bootstrap3') 回答来源:stackoverflow
is大龙 2020-03-25 09:24:24 0 浏览量 回答数 0

问题

Berkeley DB: 在c api调用中异常退出导致卡在 futex_wait 调用

C开发,使用berkeley db 4.3 (/usr/lib64/libdb-4.3.so) on RHEL5.6 with kernel 2.6.18-238_xen_AMD64. 在我的测试中 (写入 1,000,000 key/va...
a123456678 2019-12-01 20:02:16 1134 浏览量 回答数 2

问题

如何使用CREATE TABLE数据定义语言

该语句用于在OceanBase数据库中创建新表。 格式 CREATE TABLE [IF NOT EXIST] tblname (create_definition,...)[table_options] [partition_option...
云栖大讲堂 2019-12-01 21:28:42 1357 浏览量 回答数 0

回答

一、Smarty缓存的几种方式缓存机制中,分为全局缓存、部分缓存、局部缓存三种方式,后面会一一讲述,下面是缓存设置前,Smarty类方法基本目录设置如下: $smarty->Smarty(); $smarty->template_dir = $ROOT."/templates";//模板目录 $smarty->compile_dir = $ROOT."/templates_c";//编译目录 $smarty->cache_dir = $ROOT."/cache";//缓存目录 $smarty->caching = true;//是否开启缓存,值为0,1,2,0则不开启:1则开启缓存:2则可设置特殊缓存,即在加载模板页前,对局部进行缓存时间的特殊设定,后面会讲到;可不写,默认为true-开启 $smarty->cache_lifetime = "3600";//缓存时间 ,可不写,默认为3600 $smarty->compile_check = true;//是否进行编译,可不写,默认为true 缓存机制中调用模板生成缓存页面,用的一个display()方法,将会在后文中用到,这里先讲解一下: $smarty->display(string template[, string cache_id[, string compile_id]]); 第一个必须参数:template,为需显示的模板;第二个可选参数:cache_id,可指定一个缓存号,此参数是给页面缓存添加一个标识的作用;第三个可选参数:compile_id,可指定一个编译号 ,此参数是把一个模板编译成不同版本时使用,同样是起一个标识的作用,不常用。上面代码简洁、说明易懂吧!若引用创建Smarty类都不知,那下面可以省了,呵,开个玩笑!接着往下看。1、全局缓存方式定义:字面上看,意思很明了,就是为整个网站的全部页面都进行缓存生成,只要页面调用了Smarty类模板。代码实例:其实,在这段之前的基本目录设置中就讲到了,为说明,用蓝颜色标明了出来代码,只要在类中这样设置,并在页面中进行如下引用,页面即进行了缓存,$smarty->display(‘index.tpl’);而这条语句,有一个很大的缺陷,就是一个模板即一个模板页面,只生成一个缓存,而我们知道,大多网站的多数页面后面会接一些参数或不同页面调用同一个模板,比如: http://blog.unvs.cn/archives/2012_9.html http://blog.unvs.cn/archives/2012_8.html http://blog.unvs.cn/archives/2012_7.html 比方这些是调用的同一个模板生成的页面,但是又必须生成3个缓存,使用上面的语句肯定做不到,这里我们要想到一开始讲到的第二个可选参数cache_id,用一个缓存号,来区分同一个模板生成不同的页面及缓存,代码实例: $cache_id = $_GET['id'];//url中的id参数值 $smarty->display(‘index.tpl’, $cache_id);//将缓存号加入,即可完成–同一模板–不同参数–不同缓存 的功能; 到这里,有人发现,如果我的页面不止一个参数,那是不是得全部解析出来并做为缓存号?这里有一个更好的方法,推荐给大家,也是网上大多赞同的。(其实,上面一段是’废话‘,可去掉,但为了循序渐进,更好理解而写的过渡,谅)推荐的方法是:你可以直接将整个当前URL获取下来,作为cache_id加入缓存,这样无论它多少个参数,都不会存在同一个缓存页,代码实例: $url=$_SERVER['REQUEST_URI'];//获取当前页URL,有的将url进行md5加密,亦可 $smarty->display(‘index.tpl’, $url); 2、部分缓存方式定义:意思就是,网站系统的部分页面进行缓存,而一些页面不进行缓存,比方网站的注册、登录处理页面可不进行缓存。一种处理方式:在display()方法前或后面,将此模板缓存进行一次清除操作,注意保持两者参数必须一致;代码实例: $smarty->clear_cache(“index.tpl”);//此句放在display方法句前后都可以 $smarty->display(“index.tpl”);//与clear_cache方法参数必须一致 另一种处理方式:原理是一样的,因为部分缓存相当于两种情况,你可以另写一个display方法进行重构,其中一个参数判断是否进行缓存,若不,则进行clear_cache()方法处理,否则进行缓存;代码实例: function display($temp_name, $cache_id = null,$is_cache = true){ if($is_cache){ $smarty->clear_cache(“index.tpl”, $cache_id); $smarty->display(“index.tpl”, $cache_id);//此两句不解,见上面绿色代码 }else{ $smarty->display(“index.tpl”, $cache_id); }} 调用方法:self::display($temp_name, $cache_id, false);//这样设置即不进行缓存,有任何疑问可留言提出。3、局部缓存方式定义:一个页面,一些地方不进行缓存,保持动态更新,每次都加载,比如文章详细页的浏览次数、登录窗口框等。有几种可实现局部缓存的方法(反面即处理好不缓存的地方就可实现局部缓存),着重讲解1、2种方法,我觉得就可以了,不用学会那么多。a、使用SMarty引擎中内置的nocache函数,实现不缓存功能(smarty3.1.8版支持,不知smarty2+是否支持)直接在tpl或html模板页中,不缓存区域加入{nocache}不缓存内容{/nocache}即可。代码实例:处理页面:$smarty->assign("time",time());模板页面:{nocache}<{$time}>{/nocache}b、注册块方法,实现不缓存写一个no_cached方法,并调用smarty注册块函数将方法进行注册,即可实现,直接贴实例。代码实例: 处理页面:$smarty->assign("time",time()); function no_cached($param, $content){//参数$param为块参数数组,参数$content为不缓存内容 return $content; } $smarty->register_block("no_cached", “no_cached”, false);//注册块方法:register_block($tpl_func, $reg_func, $cacheable);//参数1为模板函数;参数2为需注册的函数即上面写的函数;参数3为是否进行缓存,这里必须设置为false 模板页面:{no_cached}<{$time}>{/no_cached} c、当然还有其他一些方法,比如:注册函数等,这里就不介绍了,其中注册块详细使用,请查看smarty说明书,这里就不详述了。4、缓存机制中的is_cached用法最后,说下is_cached($temp_tpl[, $cache_id])判断是否已被缓存这个方法,$temp_tpl参数为模板页,$cache_id参数为缓存号,这个方法主要用在加载模板前进行缓存判断,若不存在就加载数据,若存在直接跳过,这样就达到了缓存的最终目的。示例: if(!smarty->is_cached(‘index.tpl’)){//不存在缓存 //调用数据库,并对变量进行赋值 } $smarty->display(‘index.tpl’);//加载模板页
小旋风柴进 2019-12-02 02:01:05 0 浏览量 回答数 0

回答

你发的这些东西看不出问题, 这只不过是设置SDL音频播放参数和回调接口而已. 得看看你是如何解码的, 有没有把解码出来的数据弄丢, 不然是不会有噪音的...######我把源码发上来了 你帮我看一下 拜托了######回复 @bruce_hou : 没看到你的代码, 我也不知道怎么回事.######具体怎么处理啊 能不能详细的说一下######我把源码发上来 #include "libavformat/avformat.h" #include "libswscale/swscale.h" #include <SDL/SDL.h> #include <SDL/SDL_thread.h> #ifdef main #undef main #endif #include <stdio.h> #include <math.h> #define SDL_AUDIO_BUFFER_SIZE 1024 #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) #define MAX_VIDEOQ_SIZE (5 * 256 * 1024) #define AV_SYNC_THRESHOLD 0.01 #define AV_NOSYNC_THRESHOLD 10.0 #define FF_ALLOC_EVENT (SDL_USEREVENT) #define FF_REFRESH_EVENT (SDL_USEREVENT + 1) #define FF_QUIT_EVENT (SDL_USEREVENT + 2) #define VIDEO_PICTURE_QUEUE_SIZE 1 typedef struct PacketQueue { AVPacketList *first_pkt, *last_pkt; int nb_packets; int size; SDL_mutex *mutex; SDL_cond *cond; } PacketQueue; typedef struct VideoPicture { SDL_Overlay *bmp; int width, height; int allocated; double pts; } VideoPicture; typedef struct VideoState { AVFormatContext *pFormatCtx; int videoStream, audioStream; double audio_clock; AVStream *audio_st; PacketQueue audioq; uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; unsigned int audio_buf_size; unsigned int audio_buf_index; AVPacket audio_pkt; uint8_t *audio_pkt_data; int audio_pkt_size; int audio_hw_buf_size; double frame_timer; double frame_last_pts; double frame_last_delay; double video_clock; ///<pts of last decoded frame / predicted pts of next decoded frame AVStream *video_st; PacketQueue videoq; VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE]; int pictq_size, pictq_rindex, pictq_windex; SDL_mutex *pictq_mutex; SDL_cond *pictq_cond; SDL_Thread *parse_tid; SDL_Thread *video_tid; char filename[1024]; int quit; } VideoState; SDL_Surface *screen; VideoState *global_video_state; void packet_queue_init(PacketQueue *q) { memset(q, 0, sizeof(PacketQueue)); q->mutex = SDL_CreateMutex(); q->cond = SDL_CreateCond(); } int packet_queue_put(PacketQueue *q, AVPacket *pkt) { AVPacketList *pkt1; if(av_dup_packet(pkt) < 0) { return -1; } pkt1 = (AVPacketList *)av_malloc(sizeof(AVPacketList)); if (!pkt1) return -1; pkt1->pkt = *pkt; pkt1->next = NULL; SDL_LockMutex(q->mutex); if (!q->last_pkt) q->first_pkt = pkt1; else q->last_pkt->next = pkt1; q->last_pkt = pkt1; q->nb_packets++; q->size += pkt1->pkt.size; SDL_CondSignal(q->cond); SDL_UnlockMutex(q->mutex); return 0; } static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) { AVPacketList *pkt1; int ret; SDL_LockMutex(q->mutex); for(;;) { if(global_video_state->quit) { ret = -1; break; } pkt1 = q->first_pkt; if (pkt1) { q->first_pkt = pkt1->next; if (!q->first_pkt) q->last_pkt = NULL; q->nb_packets--; q->size -= pkt1->pkt.size; *pkt = pkt1->pkt; av_free(pkt1); ret = 1; break; } else if (!block) { ret = 0; break; } else { SDL_CondWait(q->cond, q->mutex); } } SDL_UnlockMutex(q->mutex); return ret; } double get_audio_clock(VideoState *is) { double pts; int hw_buf_size, bytes_per_sec, n; pts = is->audio_clock; hw_buf_size = is->audio_buf_size - is->audio_buf_index; bytes_per_sec = 0; n = is->audio_st->codec->channels * 2; if(is->audio_st) { bytes_per_sec = is->audio_st->codec->sample_rate * n; } if(bytes_per_sec) { pts -= (double)hw_buf_size / bytes_per_sec; } return pts; } int audio_decode_frame(VideoState *is, uint8_t *audio_buf, int buf_size, double *pts_ptr) { int len1, data_size, n; AVPacket *pkt = &is->audio_pkt; double pts; for(;;) { while(is->audio_pkt_size > 0) { data_size = buf_size; len1 = avcodec_decode_audio2(is->audio_st->codec, (int16_t *)audio_buf, &data_size, is->audio_pkt_data, is->audio_pkt_size); if(len1 < 0) { is->audio_pkt_size = 0; break; } is->audio_pkt_data += len1; is->audio_pkt_size -= len1; if(data_size <= 0) { continue; } pts = is->audio_clock; *pts_ptr = pts; n = 2 * is->audio_st->codec->channels; is->audio_clock += (double)data_size / (double)(n * is->audio_st->codec->sample_rate); return data_size; } if(pkt->data) av_free_packet(pkt); if(is->quit) { return -1; } if(packet_queue_get(&is->audioq, pkt, 1) < 0) { return -1; } is->audio_pkt_data = pkt->data; is->audio_pkt_size = pkt->size; if(pkt->pts != AV_NOPTS_VALUE) { is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; } } } void audio_callback(void *userdata, Uint8 *stream, int len) { VideoState *is = (VideoState *)userdata; int len1, audio_size; double pts; while(len > 0) { if(is->audio_buf_index >= is->audio_buf_size) { audio_size = audio_decode_frame(is, is->audio_buf, sizeof(is->audio_buf), &pts); if(audio_size < 0) { is->audio_buf_size = 1024; memset(is->audio_buf, 0, is->audio_buf_size); } else { is->audio_buf_size = audio_size; } is->audio_buf_index = 0; } len1 = is->audio_buf_size - is->audio_buf_index; if(len1 > len) len1 = len; memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1); len -= len1; stream += len1; is->audio_buf_index += len1; } } static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) { SDL_Event event; event.type = FF_REFRESH_EVENT; event.user.data1 = opaque; SDL_PushEvent(&event); return 0; } static void schedule_refresh(VideoState *is, int delay) { SDL_AddTimer(delay, sdl_refresh_timer_cb, is); } void video_display(VideoState *is) { SDL_Rect rect; VideoPicture *vp; AVPicture pict; float aspect_ratio; int w, h, x, y; int i; vp = &is->pictq[is->pictq_rindex]; if(vp->bmp) { if(is->video_st->codec->sample_aspect_ratio.num == 0) { aspect_ratio = 0; } else { aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio) * is->video_st->codec->width / is->video_st->codec->height; } if(aspect_ratio <= 0.0) { aspect_ratio = (float)is->video_st->codec->width / (float)is->video_st->codec->height; } h = screen->h; w = ((int)(h * aspect_ratio)) & -3; if(w > screen->w) { w = screen->w; h = ((int)(w / aspect_ratio)) & -3; } x = (screen->w - w) / 2; y = (screen->h - h) / 2; rect.x = x; rect.y = y; rect.w = w; rect.h = h; SDL_DisplayYUVOverlay(vp->bmp, &rect); } } void video_refresh_timer(void *userdata) { VideoState *is = (VideoState *)userdata; VideoPicture *vp; double actual_delay, delay, sync_threshold, ref_clock, diff; if(is->video_st) { if(is->pictq_size == 0) { schedule_refresh(is, 1); } else { vp = &is->pictq[is->pictq_rindex]; delay = vp->pts - is->frame_last_pts; if(delay <= 0 || delay >= 1.0) { delay = is->frame_last_delay; } is->frame_last_delay = delay; is->frame_last_pts = vp->pts; ref_clock = get_audio_clock(is); diff = vp->pts - ref_clock; sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; if(fabs(diff) < AV_NOSYNC_THRESHOLD) { if(diff <= -sync_threshold) { delay = 0; } else if(diff >= sync_threshold) { delay = 2 * delay; } } is->frame_timer += delay; actual_delay = is->frame_timer - (av_gettime() / 1000000.0); if(actual_delay < 0.010) { actual_delay = 0.010; } schedule_refresh(is, (int)(actual_delay * 1000 + 0.5)); video_display(is); if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) { is->pictq_rindex = 0; } SDL_LockMutex(is->pictq_mutex); is->pictq_size--; SDL_CondSignal(is->pictq_cond); SDL_UnlockMutex(is->pictq_mutex); } } else { schedule_refresh(is, 100); } } void alloc_picture(void *userdata) { VideoState *is = (VideoState *)userdata; VideoPicture *vp; vp = &is->pictq[is->pictq_windex]; if(vp->bmp) { // we already have one make another, bigger/smaller SDL_FreeYUVOverlay(vp->bmp); } // Allocate a place to put our YUV image on that screen vp->bmp = SDL_CreateYUVOverlay(is->video_st->codec->width, is->video_st->codec->height, SDL_YV12_OVERLAY, screen); vp->width = is->video_st->codec->width; vp->height = is->video_st->codec->height; SDL_LockMutex(is->pictq_mutex); vp->allocated = 1; SDL_CondSignal(is->pictq_cond); SDL_UnlockMutex(is->pictq_mutex); } int queue_picture(VideoState *is, AVFrame *pFrame, double pts) { VideoPicture *vp; //int dst_pix_fmt; AVPicture pict; SDL_LockMutex(is->pictq_mutex); while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !is->quit) { SDL_CondWait(is->pictq_cond, is->pictq_mutex); } SDL_UnlockMutex(is->pictq_mutex); if(is->quit) return -1; // windex is set to 0 initially vp = &is->pictq[is->pictq_windex]; if(!vp->bmp || vp->width != is->video_st->codec->width || vp->height != is->video_st->codec->height) { SDL_Event event; vp->allocated = 0; event.type = FF_ALLOC_EVENT; event.user.data1 = is; SDL_PushEvent(&event); SDL_LockMutex(is->pictq_mutex); while(!vp->allocated && !is->quit) { SDL_CondWait(is->pictq_cond, is->pictq_mutex); } SDL_UnlockMutex(is->pictq_mutex); if(is->quit) { return -1; } } static struct SwsContext *img_convert_ctx; if (img_convert_ctx == NULL) { img_convert_ctx = sws_getContext(is->video_st->codec->width, is->video_st->codec->height, is->video_st->codec->pix_fmt, is->video_st->codec->width, is->video_st->codec->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); if (img_convert_ctx == NULL) { fprintf(stderr, "Cannot initialize the conversion context\n"); exit(1); } } if(vp->bmp) { SDL_LockYUVOverlay(vp->bmp); //dst_pix_fmt = PIX_FMT_YUV420P; pict.data[0] = vp->bmp->pixels[0]; pict.data[1] = vp->bmp->pixels[2]; pict.data[2] = vp->bmp->pixels[1]; pict.linesize[0] = vp->bmp->pitches[0]; pict.linesize[1] = vp->bmp->pitches[2]; pict.linesize[2] = vp->bmp->pitches[1]; // Convert the image into YUV format that SDL uses sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, is->video_st->codec->height, pict.data, pict.linesize); SDL_UnlockYUVOverlay(vp->bmp); vp->pts = pts; if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) { is->pictq_windex = 0; } SDL_LockMutex(is->pictq_mutex); is->pictq_size++; SDL_UnlockMutex(is->pictq_mutex); } return 0; } double synchronize_video(VideoState *is, AVFrame *src_frame, double pts) { double frame_delay; if(pts != 0) { is->video_clock = pts; } else { pts = is->video_clock; } frame_delay = av_q2d(is->video_st->codec->time_base); frame_delay += src_frame->repeat_pict * (frame_delay * 0.5); is->video_clock += frame_delay; return pts; } uint64_t global_video_pkt_pts = AV_NOPTS_VALUE; int our_get_buffer(struct AVCodecContext *c, AVFrame *pic) { int ret = avcodec_default_get_buffer(c, pic); uint64_t *pts = (uint64_t *)av_malloc(sizeof(uint64_t)); *pts = global_video_pkt_pts; pic->opaque = pts; return ret; } void our_release_buffer(struct AVCodecContext *c, AVFrame *pic) { if(pic) av_freep(&pic->opaque); avcodec_default_release_buffer(c, pic); } int video_thread(void *arg) { VideoState *is = (VideoState *)arg; AVPacket pkt1, *packet = &pkt1; int len1, frameFinished; AVFrame *pFrame; double pts; pFrame = avcodec_alloc_frame(); for(;;) { if(packet_queue_get(&is->videoq, packet, 1) < 0) { // means we quit getting packets break; } pts = 0; // Save global pts to be stored in pFrame in first call global_video_pkt_pts = packet->pts; // Decode video frame len1 = avcodec_decode_video(is->video_st->codec, pFrame, &frameFinished, packet->data, packet->size); if(packet->dts == AV_NOPTS_VALUE && pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) { pts = *(uint64_t *)pFrame->opaque; } else if(packet->dts != AV_NOPTS_VALUE) { pts = packet->dts; } else { pts = 0; } pts *= av_q2d(is->video_st->time_base); // Did we get a video frame? if(frameFinished) { pts = synchronize_video(is, pFrame, pts); if(queue_picture(is, pFrame, pts) < 0) { break; } } av_free_packet(packet); } av_free(pFrame); return 0; } int stream_component_open(VideoState *is, int stream_index) { AVFormatContext *pFormatCtx = is->pFormatCtx; AVCodecContext *codecCtx; AVCodec *codec; SDL_AudioSpec wanted_spec, spec; if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams) { return -1; } // Get a pointer to the codec context for the video stream codecCtx = pFormatCtx->streams[stream_index]->codec; if(codecCtx->codec_type == CODEC_TYPE_AUDIO) { // Set audio settings from codec info wanted_spec.freq = codecCtx->sample_rate; wanted_spec.format = AUDIO_S16SYS; wanted_spec.channels = codecCtx->channels; wanted_spec.silence = 0; wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; wanted_spec.callback = audio_callback; wanted_spec.userdata = is; if(SDL_OpenAudio(&wanted_spec, &spec) < 0) { fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError()); return -1; } is->audio_hw_buf_size = spec.size; } codec = avcodec_find_decoder(codecCtx->codec_id); if(!codec || (avcodec_open(codecCtx, codec) < 0)) { fprintf(stderr, "Unsupported codec!\n"); return -1; } switch(codecCtx->codec_type) { case CODEC_TYPE_AUDIO: is->audioStream = stream_index; is->audio_st = pFormatCtx->streams[stream_index]; is->audio_buf_size = 0; is->audio_buf_index = 0; memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); packet_queue_init(&is->audioq); SDL_PauseAudio(0); break; case CODEC_TYPE_VIDEO: is->videoStream = stream_index; is->video_st = pFormatCtx->streams[stream_index]; is->frame_timer = (double)av_gettime() / 1000000.0; is->frame_last_delay = 40e-3; packet_queue_init(&is->videoq); is->video_tid = SDL_CreateThread(video_thread, is); codecCtx->get_buffer = our_get_buffer; codecCtx->release_buffer = our_release_buffer; break; default: break; } return 0; } int decode_interrupt_cb(void) { return (global_video_state && global_video_state->quit); } int decode_thread(void *arg) { VideoState *is = (VideoState *)arg; AVFormatContext *pFormatCtx; AVPacket pkt1, *packet = &pkt1; int video_index = -1; int audio_index = -1; int i; is->videoStream=-1; is->audioStream=-1; global_video_state = is; // will interrupt blocking functions if we quit! url_set_interrupt_cb(decode_interrupt_cb); // Open video file if(av_open_input_file(&pFormatCtx, is->filename, NULL, 0, NULL)!=0) return -1; // Couldn't open file is->pFormatCtx = pFormatCtx; // Retrieve stream information if(av_find_stream_info(pFormatCtx)<0) return -1; // Couldn't find stream information // Dump information about file onto standard error dump_format(pFormatCtx, 0, is->filename, 0); // Find the first video stream for(i=0; i<pFormatCtx->nb_streams; i++) { if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO && video_index < 0) { video_index=i; } if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO && audio_index < 0) { audio_index=i; } } if(audio_index >= 0) { stream_component_open(is, audio_index); } if(video_index >= 0) { stream_component_open(is, video_index); } if(is->videoStream < 0 || is->audioStream < 0) { fprintf(stderr, "%s: could not open codecs\n", is->filename); goto fail; } // main decode loop for(;;) { if(is->quit) { break; } // seek stuff goes here if(is->audioq.size > MAX_AUDIOQ_SIZE || is->videoq.size > MAX_VIDEOQ_SIZE) { SDL_Delay(10); continue; } if(av_read_frame(is->pFormatCtx, packet) < 0) { if(url_ferror(pFormatCtx->pb) == 0) { SDL_Delay(100); continue; } else { break; } } // Is this a packet from the video stream? if(packet->stream_index == is->videoStream) { packet_queue_put(&is->videoq, packet); } else if(packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet); } else { av_free_packet(packet); } } while(!is->quit) { SDL_Delay(100); } fail: { SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); } return 0; } int main(int argc, char *argv[]) { SDL_Event event; VideoState *is; is = (VideoState *)av_mallocz(sizeof(VideoState)); if(argc < 2) { fprintf(stderr, "Usage: test <file>\n"); exit(1); } // Register all formats and codecs av_register_all(); if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); exit(1); } // Make a screen to put our video #ifndef __DARWIN__ screen = SDL_SetVideoMode(640, 480, 0, 0); #else screen = SDL_SetVideoMode(640, 480, 24, 0); #endif if(!screen) { fprintf(stderr, "SDL: could not set video mode - exiting\n"); exit(1); } //pstrcpy(is->filename, sizeof(is->filename), argv[1]); strcpy(is->filename,argv[1]); is->pictq_mutex = SDL_CreateMutex(); is->pictq_cond = SDL_CreateCond(); schedule_refresh(is, 40); is->parse_tid = SDL_CreateThread(decode_thread, is); if(!is->parse_tid) { av_free(is); return -1; } for(;;) { SDL_WaitEvent(&event); switch(event.type) { case FF_QUIT_EVENT: case SDL_QUIT: is->quit = 1; SDL_Quit(); exit(0); break; case FF_ALLOC_EVENT: alloc_picture(event.user.data1); break; case FF_REFRESH_EVENT: video_refresh_timer(event.user.data1); break; default: break; } } return 0; } 你帮我看一下######你有没有最新的ffmpeg转码示范代码啊######回复 @Jack.arain : 给我一个示范代码好不,这上面的代码是一个示范代码,我把 avcodec_decode_audio3,######看了下代码, 不知道你用的是哪个版本的ffmpeg, 但你这个代码是非常老的了, 另外, 在ffmpeg后期的版本中, avcodec_decode_audio函数可能解码出来的数据要比实际的数据要长, 需要使用av_samples_get_buffer_size来获得实际大小.###### C++我不懂,不过音视频解码的内核我写过不少。如果内核解别的不出错,那么噪音基本来源于输出的音频PCM的BUF不干净或者输入的频段信息有缺失,某个通道没有数据进入。前者你的输出BUF可能被别的代码(包括解码本身)写操作过。你查下有没有内存泄露的问题。后者,是你的输入不全的问题。更大概率是后者。前者要定期加入噪音的概率还是比较小。 这类问题的检测方法是外围做最简单的调用。验证调用方法和内核模块都没有问题。然后再堆叠其他系统模块上去。 ######的确是旧的代码,现在新的都用上了avcodec_decode_audio4了,你的ffmpeg库是什么版本的,新的版本有libswresample,可以帮你的音频做重采样,这样播放出来就不会有噪声了,如果想看事例代码,就看你的ffmpeg源码里的ffplay.c吧,里面的接口都和你的ffmpeg对应的,看看人家是怎么处理音频的,希望对你有用。
爱吃鱼的程序员 2020-06-05 13:33:51 0 浏览量 回答数 0

问题

第三章 – 布局,块和模板:报错

深入理解Magento – 第三章 – 布局,块和模板 深入理解Magento – 第三章 – 布局,块和模板:报错 深入理解Magento – 第三章 – 布局,块和模板 深入理...
kun坤 2020-06-06 16:14:05 0 浏览量 回答数 1

问题

正则表达式函数是什么?

所有的正则表达式函数都使用Java样式的语法。 当使用多行模式(通过(?m)标志启用)时,只有n被识别为行终止符。 (?d&#x...
nicenelly 2019-12-01 21:26:40 1396 浏览量 回答数 0

回答

tl; dr:您可能应该使用一维方法。 注意:在不填充书本的情况下比较动态1d或动态2d存储模式时,无法深入研究影响性能的细节,因为代码的性能取决于很多参数。如有可能,进行配置文件。 1.什么更快? 对于密集矩阵,一维方法可能更快,因为它提供了更好的内存局部性以及更少的分配和释放开销。 2.较小的是? 与2D方法相比,Dynamic-1D消耗的内存更少。后者还需要更多分配。 备注 我出于以下几个原因给出了一个很长的答案,但我想首先对您的假设做一些评论。 我可以想象,重新计算1D数组(y + x * n)的索引可能比使用2D数组(x,y)慢 让我们比较这两个函数: int get_2d (int **p, int r, int c) { return p[r][c]; } int get_1d (int *p, int r, int c) { return p[c + C*r]; } Visual Studio 2015 RC为这些功能(启用了优化功能)生成的(非内联)程序集是: ?get_1d@@YAHPAHII@Z PROC push ebp mov ebp, esp mov eax, DWORD PTR _c$[ebp] lea eax, DWORD PTR [eax+edx*4] mov eax, DWORD PTR [ecx+eax*4] pop ebp ret 0 ?get_2d@@YAHPAPAHII@Z PROC push ebp mov ebp, esp mov ecx, DWORD PTR [ecx+edx*4] mov eax, DWORD PTR _c$[ebp] mov eax, DWORD PTR [ecx+eax*4] pop ebp ret 0 区别是mov(2d)与lea(1d)。前者的延迟为3个周期,最大吞吐量为每个周期2个,而后者的延迟为2个周期,最大吞吐量为每个周期3个。(根据指令表-Agner Fog, 由于差异很小,我认为索引重新计算不会产生很大的性能差异。我希望几乎不可能将这种差异本身确定为任何程序的瓶颈。 这将我们带到下一个(也是更有趣的)点: ...但是我可以想象一维可能在CPU缓存中... 是的,但是2d也可能在CPU缓存中。有关为什么1d仍然更好的说明,请参见缺点:内存局部性。 长答案,或者为什么对于简单 /小的矩阵,动态二维数据存储(指针到指针或向量矢量)是“不好的” 。 注意:这是关于动态数组/分配方案[malloc / new / vector等]。静态2D数组是一个连续的内存块,因此不受我将在此处介绍的不利影响。 问题 为了能够理解为什么动态数组的动态数组或向量的矢量最有可能不是选择的数据存储模式,您需要了解此类结构的内存布局。 使用指针语法的示例案例 int main (void) { // allocate memory for 4x4 integers; quick & dirty int ** p = new int*[4]; for (size_t i=0; i<4; ++i) p[i] = new int[4]; // do some stuff here, using p[x][y] // deallocate memory for (size_t i=0; i<4; ++i) delete[] p[i]; delete[] p; } 缺点 内存位置 对于此“矩阵”,您分配一个包含四个指针的块和四个包含四个整数的块。所有分配都不相关,因此可以导致任意存储位置。 下图将使您了解内存的外观。 对于真正的二维情况: 紫色正方形是其p自身占据的存储位置。 绿色方块将存储区域p点组装为(4 x int*)。 4个连续的蓝色方块的4个区域是每个int*绿色区域所指向的区域 对于在1d情况下映射的2d: 绿色方块是唯一需要的指针 int * 蓝色方块组合了所有矩阵元素的存储区域(16 x int)。 实际2D与映射2D内存布局 这意味着(例如,使用左侧布局时)(例如,使用缓存),与连续存储模式(如右侧所示)相比,您可能会发现性能较差。 假设高速缓存行是“一次传输到高速缓存中的数据量”,并想象一个程序一个接一个地访问整个矩阵。 如果您具有正确对齐的32位值的4 4矩阵,则具有64字节高速缓存行(典型值)的处理器能够“一次性”读取数据(4 * 4 * 4 = 64字节)。如果您开始处理而缓存中还没有数据,则将面临缓存未命中,并且将从主内存中获取数据。由于且仅当连续存储(并正确对齐)时,此负载才能装入整个缓存行,因此可以立即读取整个矩阵。处理该数据时可能不会再有任何遗漏。 在动态的“真实二维”系统中,每行/列的位置都不相关,处理器需要分别加载每个内存位置。即使只需要64个字节,在最坏的情况下,为4个不相关的内存位置加载4条高速缓存行实际上会传输256个字节并浪费75%的吞吐量带宽。如果使用2d方案处理数据,您将再次在第一个元素上遇到缓存未命中(如果尚未缓存)。但是现在,从主内存中第一次加载后,只有第一行/列会在缓存中,因为所有其他行都位于内存中的其他位置,并且不与第一行/列相邻。一旦到达新的行/列,就会再次出现高速缓存未命中,并从主内存执行下一次加载。 长话短说:2d模式具有较高的缓存未命中率,而1d方案由于数据的局部性而具有更好的性能潜力。 频繁分配/取消分配 N + 1创建所需的NxM(4×4)矩阵需要多达(4 + 1 = 5)个分配(使用new,malloc,allocator :: allocate或其他方法)。 也必须应用相同数量的适当的各自的重新分配操作。 因此,与单个分配方案相比,创建/复制此类矩阵的成本更高。 随着行数的增加,情况变得更加糟糕。 内存消耗开销 我假设int的大小为32位,指针的大小为32位。(注意:系统依赖性。) 让我们记住:我们要存储一个4×4 int矩阵,表示64个字节。 对于NxM矩阵,使用提出的指针对指针方案存储,我们消耗了 NMsizeof(int) [实际的蓝色数据] + Nsizeof(int) [绿色指针] + sizeof(int**) [紫罗兰色变量p]字节。 444 + 44 + 4 = 84在本示例的情况下,这会使字节变多,使用时甚至会变得更糟std::vector<std::vector >。对于4 x 4 int ,它将需要N * M * sizeof(int)+ N * sizeof(vector )+ sizeof(vector<vector >)字节,即4 44 + 416 + 16 = 144总共字节,共64个字节。 另外-根据所使用的分配器-每个单独的分配可能(并且很可能会)还有16个字节的内存开销。(一些“信息字节”用于存储已分配的字节数,以进行适当的重新分配。) 这意味着最坏的情况是: N*(16+Msizeof(int)) + 16+Nsizeof(int*) + sizeof(int**) = 4*(16+44) + 16+44 + 4 = 164 bytes ! Overhead: 156% 开销的份额将随着矩阵大小的增加而减少,但仍然存在。 内存泄漏的风险 一堆分配需要适当的异常处理,以避免在其中一个分配失败的情况下发生内存泄漏!您需要跟踪分配的内存块,并且在释放内存时一定不要忘记它们。 如果new无法运行内存并且无法分配下一行(特别是在矩阵很大时),std::bad_alloc则抛出a new。 例: 在上面提到的new / delete示例中,如果要避免发生bad_alloc异常时的泄漏,我们将面临更多代码。 // allocate memory for 4x4 integers; quick & dirty size_t const N = 4; // we don't need try for this allocation // if it fails there is no leak int ** p = new int*[N]; size_t allocs(0U); try { // try block doing further allocations for (size_t i=0; i<N; ++i) { p[i] = new int[4]; // allocate ++allocs; // advance counter if no exception occured } } catch (std::bad_alloc & be) { // if an exception occurs we need to free out memory for (size_t i=0; i<allocs; ++i) delete[] p[i]; // free all alloced p[i]s delete[] p; // free p throw; // rethrow bad_alloc } /* do some stuff here, using p[x][y] */ // deallocate memory accoding to the number of allocations for (size_t i=0; i<allocs; ++i) delete[] p[i]; delete[] p; 摘要 在某些情况下,“真实的2d”内存布局适合并且有意义(即,如果每行的列数不是恒定的),但是在最简单和常见的2D数据存储情况下,它们只会使代码的复杂性膨胀,并降低性能和程序的内存效率。 另类 您应该使用连续的内存块,并将行映射到该内存块。 做到这一点的“ C ++方式”可能是编写一个类来管理您的内存,同时考虑诸如 什么是三法则? 资源获取是什么意思初始化(RAII)? C ++概念:容器(在cppreference.com上) 例 为了提供这样一个类的外观的想法,下面是一个具有一些基本功能的简单示例: 二维尺寸可构造 2d可调整大小 operator(size_t, size_t) 用于2行主要元素访问 at(size_t, size_t) 用于检查的第二行主要元素访问 满足容器的概念要求 资源: #include #include #include #include namespace matrices { template class simple { public: // misc types using data_type = std::vector ; using value_type = typename std::vector ::value_type; using size_type = typename std::vector ::size_type; // ref using reference = typename std::vector ::reference; using const_reference = typename std::vector ::const_reference; // iter using iterator = typename std::vector ::iterator; using const_iterator = typename std::vector ::const_iterator; // reverse iter using reverse_iterator = typename std::vector ::reverse_iterator; using const_reverse_iterator = typename std::vector ::const_reverse_iterator; // empty construction simple() = default; // default-insert rows*cols values simple(size_type rows, size_type cols) : m_rows(rows), m_cols(cols), m_data(rows*cols) {} // copy initialized matrix rows*cols simple(size_type rows, size_type cols, const_reference val) : m_rows(rows), m_cols(cols), m_data(rows*cols, val) {} // 1d-iterators iterator begin() { return m_data.begin(); } iterator end() { return m_data.end(); } const_iterator begin() const { return m_data.begin(); } const_iterator end() const { return m_data.end(); } const_iterator cbegin() const { return m_data.cbegin(); } const_iterator cend() const { return m_data.cend(); } reverse_iterator rbegin() { return m_data.rbegin(); } reverse_iterator rend() { return m_data.rend(); } const_reverse_iterator rbegin() const { return m_data.rbegin(); } const_reverse_iterator rend() const { return m_data.rend(); } const_reverse_iterator crbegin() const { return m_data.crbegin(); } const_reverse_iterator crend() const { return m_data.crend(); } // element access (row major indexation) reference operator() (size_type const row, size_type const column) { return m_data[m_cols*row + column]; } const_reference operator() (size_type const row, size_type const column) const { return m_data[m_cols*row + column]; } reference at() (size_type const row, size_type const column) { return m_data.at(m_cols*row + column); } const_reference at() (size_type const row, size_type const column) const { return m_data.at(m_cols*row + column); } // resizing void resize(size_type new_rows, size_type new_cols) { // new matrix new_rows times new_cols simple tmp(new_rows, new_cols); // select smaller row and col size auto mc = std::min(m_cols, new_cols); auto mr = std::min(m_rows, new_rows); for (size_type i(0U); i < mr; ++i) { // iterators to begin of rows auto row = begin() + i*m_cols; auto tmp_row = tmp.begin() + i*new_cols; // move mc elements to tmp std::move(row, row + mc, tmp_row); } // move assignment to this *this = std::move(tmp); } // size and capacity size_type size() const { return m_data.size(); } size_type max_size() const { return m_data.max_size(); } bool empty() const { return m_data.empty(); } // dimensionality size_type rows() const { return m_rows; } size_type cols() const { return m_cols; } // data swapping void swap(simple &rhs) { using std::swap; m_data.swap(rhs.m_data); swap(m_rows, rhs.m_rows); swap(m_cols, rhs.m_cols); } private: // content size_type m_rows{ 0u }; size_type m_cols{ 0u }; data_type m_data{}; }; template void swap(simple & lhs, simple & rhs) { lhs.swap(rhs); } template bool operator== (simple const &a, simple const &b) { if (a.rows() != b.rows() || a.cols() != b.cols()) { return false; } return std::equal(a.begin(), a.end(), b.begin(), b.end()); } template bool operator!= (simple const &a, simple const &b) { return !(a == b); } } 请注意以下几点: T需要满足使用的std::vector成员函数的要求 operator() 不执行任何“范围”检查 无需自己管理数据 不需要析构函数,复制构造函数或赋值运算符 因此,您不必费心为每个应用程序进行适当的内存处理,而只需为编写的类一次即可。 限制条件 在某些情况下,动态“真实”二维结构是有利的。例如,如果 矩阵非常大且稀疏(如果甚至不需要分配任何行,但可以使用nullptr对其进行处理),或者 这些行没有相同数量的列(也就是说,如果您根本没有矩阵,而只有另一个二维结构)。
保持可爱mmm 2020-02-09 13:47:55 0 浏览量 回答数 0

问题

oracle数据库基础知识精讲视频分享!

[size=;font-size:10.5000pt,10.5000pt] 课程简介:数据库基础知识、Oracle的环境搭建、Oracle体系结构、SQL语言基础、函数的使用、约束、索引、数据字典、分组查询、多表连接查...
sgkj123 2019-12-01 20:58:52 2127 浏览量 回答数 0

问题

深入理解Magento – 第七章 – 自定义Magento系统配置 :报错

深入理解Magento 作者:Alan Storm 翻译:Hailong Zhang 第七章 – 自定义Magento系统配置 Magento拥有十分强大的后台管理系统。作为一名开发人员,这套...
kun坤 2020-06-14 15:21:31 0 浏览量 回答数 1

问题

第七章 – 自定义Magento系统配置:配置报错 

深入理解Magento – 深入理解Magento 作者: Alan Storm 翻译: Hailong Zhang 第七章 – 自定义Magento系统配置 Magento拥有十分强大的后台管理系统。作为一...
kun坤 2020-06-02 14:47:13 0 浏览量 回答数 1

问题

深入理解Magento – 第七章 – 自定义Magento系统配置 - 配置报错

" 深入理解Magento 作者:Alan Storm 翻译:Hailong Zhang 第七章 – 自定义Magento系统配置 Magento拥有十分强大的后台管理系统。作为一名开发人员&#x...
montos 2020-06-03 20:29:30 2 浏览量 回答数 1

问题

深入理解Magento - 第一章 - Magento强大的配置系统:报错 

深入理解Magento 作者: Alan Storm 翻译: zhlmmc 前言 我从2007年开始使用Magento,应该算是国内第一批使用Magento的用户。但是我却从来没有认真研究过Mag...
kun坤 2020-06-04 21:14:35 5 浏览量 回答数 1

回答

HTML通常我们使用以下html结构,我们给复选框定义id#checkbox_a1,然后使用label的for属性与之关联,这样的话,用户点击label的时候,实际上就相当于点击了#checkbox_a1。`check `CSS通过label和checkbox,我们可以将checkbox隐藏,而将label制作为各种漂亮超酷的复选框样式。我们可以使用:before和:after伪元素来制作各种效果,如滑动按钮的效果。这些效果都可以通过相邻兄弟选择器来选择与checkbox相邻的label来实现,下面是一个简单的例子: .chk_1 { display: none; } .chk_1 + label { background-color: #FFF; border: 1px solid #C1CACA; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), inset 0px -15px 10px -12px rgba(0, 0, 0, 0.05); padding: 9px; border-radius: 5px; display: inline-block; position: relative; margin-right: 30px; } .chk_1 + label:active { box-shadow: 0 1px 2px rgba(0,0,0,0.05), inset 0px 1px 3px rgba(0,0,0,0.1); } .chk_1:checked + label { background-color: #ECF2F7; border: 1px solid #92A1AC; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), inset 0px -15px 10px -12px rgba(0, 0, 0, 0.05), inset 15px 10px -12px rgba(255, 255, 255, 0.1); color: #243441; } .chk_1:checked + label:after { content: '\2714'; //勾选符号 position: absolute; top: 0px; left: 0px; color: #758794; width: 100%; text-align: center; font-size: 1.4em; padding: 1px 0 0 0; vertical-align: text-top; } 浏览页面效果,当点击label的时候,复选框出现勾选符号,表示选中状态,再次点击时,勾选符号消失,表示取消选中状态。DEMO中,我们提供了4个示例,基本可以满足页面常见的复选框样式需求,有需要的可以直接下载源代码,复制css样式即可。你也可以根据项目需求对css样式进行适当修改。补充说明复选框的美化效果可以在IE9+浏览器中支持,那么ie8及以下浏览器需要恢复默认样式,使用以下代码: <!--[if lte IE 8]> <link href="ie8.css" rel="stylesheet" />
小旋风柴进 2019-12-02 02:31:16 0 浏览量 回答数 0

回答

python中的队列分类可分为两种:1.线程Queue,也就是普通的Queue2.进程Queue。Queue的种类:FIFO: Queue.Queue(maxsize=0)FIFO即First in First Out,先进先出。Queue提供了一个基本的FIFO容器,使用方法很简单,maxsize是个整数,指明了队列中能存放的数据个数的上限。一旦达到上限,插入会导致阻塞,直到队列中的数据被消费掉。如果maxsize小于或者等于0,队列大小没有限制。LIFOQueue.LifoQueue(maxsize=0)LIFO即Last in First Out,后进先出。与栈的类似,使用也很简单,maxsize用法同上priorityclass Queue.PriorityQueue(maxsize=0)构造一个优先队列。maxsize用法同上。基本方法:   Queue.Queue(maxsize=0) FIFO, 如果maxsize小于1就表示队列长度无限 Queue.LifoQueue(maxsize=0) LIFO, 如果maxsize小于1就表示队列长度无限 Queue.qsize() 返回队列的大小 Queue.empty() 如果队列为空,返回True,反之False Queue.full() 如果队列满了,返回True,反之False Queue.get([block[, timeout]]) 读队列,timeout等待时间 Queue.put(item, [block[, timeout]]) 写队列,timeout等待时间 Queue.queue.clear() 清空队列 其他: task_done()意味着之前入队的一个任务已经完成。由队列的消费者线程调用。每一个get()调用得到一个任务,接下来的task_done()调用告诉队列该任务已经处理完毕。如果当前一个join()正在阻塞,它将在队列中的所有任务都处理完时恢复执行(即每一个由put()调用入队的任务都有一个对应的task_done()调用)。join()阻塞调用线程,直到队列中的所有任务被处理掉。只要有数据被加入队列,未完成的任务数就会增加。当消费者线程调用task_done()(意味着有消费者取得任务并完成任务),未完成的任务数就会减少。当未完成的任务数降到0,join()解除阻塞。
大财主 2019-12-02 01:06:53 0 浏览量 回答数 0

问题

恢复云数据库MySQL的备份文件到自建数据库

云数据库MySQL版使用开源软件Percona Xtrabackup对数据库进行备份,所以您可以使用该软件将云数据库MySQL的备份文件恢复到自建数据库中,本文将介绍详细的操作步骤。 关于云数据库MySQL版如何...
云栖大讲堂 2019-12-01 21:32:16 2037 浏览量 回答数 0

回答

什么意思?不能循环读取数据,存起来,然后再打印?还是因为你没办法判断数据什么时候结束? ######就是我手上有一个终端,向连在COM1上的接收器发送数据,发送完一条数据后控制台上马上现实这条数据,我想实现的效果是一行显示一条数据,现在的情况是一条数据分成了几行显示!我如果用循环的方式一个一个的读字节,就会把以前输入的数据也打印出来,我只想打印当前这条数据,一行一条数据。######串口性能有限,不同的串口设备之间都有不同,只能是被动的去接受数据,串口通讯一定要有协议,否则不好搞,不知道数据到底发完还是没发完######@广隶 : 判断不了,要从协议里规定这次通讯有多少长度的字符。怎么发送根本不好判断,17个字节,可能一次一个字节17次发过来,也可一次性发过来,甚至首位加几个字符发过来。所以写一定要有协议在里面规定通讯到底有多长。######串口方面的东西我最近才接触,我写的这个第一次打印可以一次打印17位内的数据,以后就打印14位后剩下的另起一行打印,14位后的数据好像是又读了一遍串口。怎么去判断接收器能接受多少位的数据?请指教。######对于分给终端的数据一般是有限制的,不能发太多,否则终端会吃不消。这个要看设备的制造商的文档了。###### 我把代码贴出来,有哪位大牛帮我看看,谢谢啦! public class Test3 { private static String str; public void init(){ try { CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier("COM1"); System.out.println(portId.getName()+":开启啦"); @SuppressWarnings("unused")        ReadCom readCom =new ReadCom(portId); } catch (NoSuchPortException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (PortInUseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public class ReadCom implements Runnable,SerialPortEventListener{ InputStream input = System.in; SerialPort serialPort; Thread readThread; public ReadCom(CommPortIdentifier portId) throws PortInUseException, IOException{ serialPort = (SerialPort) portId.open("test",2000); serialPort.setInputBufferSize(1024); input=serialPort.getInputStream(); try { serialPort.addEventListener(this); } catch (TooManyListenersException e) { // TODO Auto-generated catch block e.printStackTrace(); } serialPort.notifyOnDataAvailable(true); try { serialPort.setSerialPortParams(115200,  SerialPort.DATABITS_8,  SerialPort.STOPBITS_1,  SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) { // TODO Auto-generated catch block e.printStackTrace(); } readThread = new Thread(this); readThread.start(); } @Override public void run() { // TODO Auto-generated method stub } @Override public void serialEvent(SerialPortEvent event) { switch (event.getEventType()) { case SerialPortEvent.BI: case SerialPortEvent.OE: case SerialPortEvent.FE: case SerialPortEvent.PE: case SerialPortEvent.CD: case SerialPortEvent.CTS: case SerialPortEvent.DSR: case SerialPortEvent.OUTPUT_BUFFER_EMPTY: break; case SerialPortEvent.DATA_AVAILABLE: byte[] readBuffer  =  new byte[512];    try { while (input.available()>0) { int len = input.read(readBuffer); str = new String(readBuffer,0,len); Memcached mcc = Memcached.getInstance(); mcc.add("test", str); System.out.println("内容长度:"+len); System.out.println("内容:"+str); } } catch (IOException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws IOException { Test3 test3 = new Test3(); test3.init(); } } ###### 引用来自“广隶”的答案 我把代码贴出来,有哪位大牛帮我看看,谢谢啦! public class Test3 { private static String str; public void init(){ try { CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier("COM1"); System.out.println(portId.getName()+":开启啦"); @SuppressWarnings("unused")        ReadCom readCom =new ReadCom(portId); } catch (NoSuchPortException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (PortInUseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public class ReadCom implements Runnable,SerialPortEventListener{ InputStream input = System.in; SerialPort serialPort; Thread readThread; public ReadCom(CommPortIdentifier portId) throws PortInUseException, IOException{ serialPort = (SerialPort) portId.open("test",2000); serialPort.setInputBufferSize(1024); input=serialPort.getInputStream(); try { serialPort.addEventListener(this); } catch (TooManyListenersException e) { // TODO Auto-generated catch block e.printStackTrace(); } serialPort.notifyOnDataAvailable(true); try { serialPort.setSerialPortParams(115200,  SerialPort.DATABITS_8,  SerialPort.STOPBITS_1,  SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) { // TODO Auto-generated catch block e.printStackTrace(); } readThread = new Thread(this); readThread.start(); } @Override public void run() { // TODO Auto-generated method stub } @Override public void serialEvent(SerialPortEvent event) { switch (event.getEventType()) { case SerialPortEvent.BI: case SerialPortEvent.OE: case SerialPortEvent.FE: case SerialPortEvent.PE: case SerialPortEvent.CD: case SerialPortEvent.CTS: case SerialPortEvent.DSR: case SerialPortEvent.OUTPUT_BUFFER_EMPTY: break; case SerialPortEvent.DATA_AVAILABLE: byte[] readBuffer  =  new byte[512];    try { while (input.available()>0) { int len = input.read(readBuffer); str = new String(readBuffer,0,len); Memcached mcc = Memcached.getInstance(); mcc.add("test", str); System.out.println("内容长度:"+len); System.out.println("内容:"+str); } } catch (IOException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws IOException { Test3 test3 = new Test3(); test3.init(); } } 你这样是可以收到收据的,但是使用串口设备的终端机往往都是单片机,性能极为有限,往往不会一次发送大量数据,所以收到的数据基本都是碎片一块一块的。 在串口接收数据的时候需要一个协议,用这个协议来确保数据的正确性,比如数据长度,那么你就可以先直到长度,然后不停接收数据直到收完为止,另外协议还可以保证双发同步性,如果串口双方同时往对方发数据,这个时候可能会造成不可预料的结果。 ###### 引用来自“Monkey”的答案 引用来自“广隶”的答案 我把代码贴出来,有哪位大牛帮我看看,谢谢啦! public class Test3 { private static String str; public void init(){ try { CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier("COM1"); System.out.println(portId.getName()+":开启啦"); @SuppressWarnings("unused")        ReadCom readCom =new ReadCom(portId); } catch (NoSuchPortException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (PortInUseException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public class ReadCom implements Runnable,SerialPortEventListener{ InputStream input = System.in; SerialPort serialPort; Thread readThread; public ReadCom(CommPortIdentifier portId) throws PortInUseException, IOException{ serialPort = (SerialPort) portId.open("test",2000); serialPort.setInputBufferSize(1024); input=serialPort.getInputStream(); try { serialPort.addEventListener(this); } catch (TooManyListenersException e) { // TODO Auto-generated catch block e.printStackTrace(); } serialPort.notifyOnDataAvailable(true); try { serialPort.setSerialPortParams(115200,  SerialPort.DATABITS_8,  SerialPort.STOPBITS_1,  SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) { // TODO Auto-generated catch block e.printStackTrace(); } readThread = new Thread(this); readThread.start(); } @Override public void run() { // TODO Auto-generated method stub } @Override public void serialEvent(SerialPortEvent event) { switch (event.getEventType()) { case SerialPortEvent.BI: case SerialPortEvent.OE: case SerialPortEvent.FE: case SerialPortEvent.PE: case SerialPortEvent.CD: case SerialPortEvent.CTS: case SerialPortEvent.DSR: case SerialPortEvent.OUTPUT_BUFFER_EMPTY: break; case SerialPortEvent.DATA_AVAILABLE: byte[] readBuffer  =  new byte[512];    try { while (input.available()>0) { int len = input.read(readBuffer); str = new String(readBuffer,0,len); Memcached mcc = Memcached.getInstance(); mcc.add("test", str); System.out.println("内容长度:"+len); System.out.println("内容:"+str); } } catch (IOException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws IOException { Test3 test3 = new Test3(); test3.init(); } } 你这样是可以收到收据的,但是使用串口设备的终端机往往都是单片机,性能极为有限,往往不会一次发送大量数据,所以收到的数据基本都是碎片一块一块的。 在串口接收数据的时候需要一个协议,用这个协议来确保数据的正确性,比如数据长度,那么你就可以先直到长度,然后不停接收数据直到收完为止,另外协议还可以保证双发同步性,如果串口双方同时往对方发数据,这个时候可能会造成不可预料的结果。 谢谢你Monkey,我这个问题解决了!是你的答案给我启示。。。 ######我再补充一点,有些设备会往里加数据。特别是首位添加额外的字节,当然有些肯是故意加上去保证完整数据都会发过来。###### 楼主,您好!您后来是怎么解决的,能不能把源代码发给我,我邮箱是1416149633@QQ.COM,不尽感激,我是位自学者。 ######楼主解决了吗?求解决思路
kun坤 2020-06-07 22:36:33 0 浏览量 回答数 0

问题

Rails 4.0 先睹为快:作业队列 Run, baby, run!:报错

Rails 最近增加了一个作业队列系统,让我们来看看如何使用。 Run, baby, run! 这个队列 API 非常简单,你将对象放到队列中,而这个对象需要提供一个名为 run 的方法...
kun坤 2020-06-06 13:47:07 0 浏览量 回答数 1

问题

OceanBase和TiDB  Sysbench测试对比

1. 环境准备 主机 CPU E5-2430 0 @ 2.20GHz *24 内存 8G *12 DISK SATA 2T *11 用LVM管理 网卡千兆 TiDB  7台机器:  ...
mq4096 2019-12-01 21:44:04 14565 浏览量 回答数 8

问题

HBase高性能随机查询之道 – HFile原理解析

在各色数据库系统百花齐放的今天,能让大家铭记的,往往是一个数据库所能带给大家的差异化能力。正如梁宁老师的产品思维课程中所讲到的,这是一个数据库系统所能带给产品使用者的”确定性”。 差异化能力通常需要...
pandacats 2019-12-20 20:57:14 0 浏览量 回答数 0

问题

模拟登录163邮箱

项目要求:采用HTTP模拟系统自动登录到163邮箱,取对应主题下的邮件,打开邮件获取邮件内容 模拟登录,首先就是抓包,分析通讯数据包,并构造相应的数据包 ...
游客bnlxddh3fwntw 2020-04-25 14:23:37 14 浏览量 回答数 1

回答

索引,索引!!!为经常查询的字段建索引!! 但也不能过多地建索引。insert和delete等改变表记录的操作会导致索引重排,增加数据库负担。优化目标1.减少 IO 次数 IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当然,也是收效最明显的优化手段。2.降低 CPU 计算 除了 IO 瓶颈之外,SQL优化中需要考虑的就是 CPU 运算量的优化了。order by, group by,distinct … 都是消耗 CPU 的大户(这些操作基本上都是 CPU 处理内存中的数据比较运算)。当我们的 IO 优化做到一定阶段之后,降低 CPU 计算也就成为了我们 SQL 优化的重要目标优化方法改变 SQL 执行计划 明确了优化目标之后,我们需要确定达到我们目标的方法。对于 SQL 语句来说,达到上述2个目标的方法其实只有一个,那就是改变 SQL 的执行计划,让他尽量“少走弯路”,尽量通过各种“捷径”来找到我们需要的数据,以达到 “减少 IO 次数” 和 “降低 CPU 计算” 的目标分析复杂的SQL语句explain 例如: mysql> explain select from (select from ( select * from t3 where id=3952602) a) b; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 2 DERIVED system NULL NULL NULL NULL 1 3 DERIVED t3 const PRIMARY,idx_t3_id PRIMARY 4 1 很显然这条SQL是从里向外的执行,就是从id=3 向上执行.show show tables或show tables from database_name; // 显示当前数据库中所有表的名称 show databases; // 显示mysql中所有数据库的名称 show columns from table_name from database_name; 或MySQL show columns from database_name.table_name; // 显示表中列名称 show grants for user_name@localhost; // 显示一个用户的权限,显示结果类似于grant 命令 show index from table_name; // 显示表的索引 show status; // 显示一些系统特定资源的信息,例如,正在运行的线程数量 show variables; // 显示系统变量的名称和值show processlist; // 显示系统中正在运行的所有进程,也就是当前正在执行的查询。 show table status; // 显示当前使用或者指定的database中的每个表的信息。信息包括表类型和表的最新更新时间 show privileges; // 显示服务器所支持的不同权限 show create database database_name; // 显示create database 语句是否能够创建指定的数据库 show create table table_name; // 显示create database 语句是否能够创建指定的数据库 show engies; // 显示安装以后可用的存储引擎和默认引擎。 show innodb status; // 显示innoDB存储引擎的状态 show logs; // 显示BDB存储引擎的日志 show warnings; // 显示最后一个执行的语句所产生的错误、警告和通知 show errors; // 只显示最后一个执行语句所产生的错误关于enum 存在争议。 对于取值有限且固定的字段,推荐使用enum而非varchar。但是!!其他数据库可能不支持,导致了难于迁移的问题。开启缓存查询 对于完全相同的sql,使用已经存在的执行计划,从而跳过解析和生成执行计划的过程。 应用场景:有一个不经常变更的表,且服务器收到该表的大量相同查询。对于频繁更新的表,查询缓存是不适合的 Mysql 判断是否命中缓存的办法很简单,首先会将要缓存的结果放在引用表中,然后使用查询语句,数据库名称,客户端协议的版本等因素算出一个hash值,这个hash值与引用表中的结果相关联。如果在执行查询时,根据一些相关的条件算出的hash值能与引用表中的数据相关联,则表示查询命中 查询必须是完全相同的(逐字节相同)才能够被认为是相同的。另外,同样的查询字符串由于其它原因可能认为是不同的。使用不同的数据库、不同的协议版本或者不同 默认字符集的查询被认为是不同的查询并且分别进行缓存。 下面sql查询缓存认为是不同的: SELECT * FROM tbl_name Select * from tbl_name 缓存机制失效的场景 如果查询语句中包含一些不确定因素时(例如包含 函数Current()),该查询不会被缓存,不确定因素主要包含以下情况 · 引用了一些返回值不确定的函数 · 引用自定义函数(UDFs)。 · 引用自定义变量。 · 引用mysql系统数据库中的表。 · 下面方式中的任何一种: SELECT ...IN SHARE MODE SELECT ...FOR UPDATE SELECT ...INTO OUTFILE ... SELECT ...INTO DUMPFILE ... SELECT * FROM ...WHERE autoincrement_col IS NULL · 使用TEMPORARY表。 · 不使用任何表。 · 用户有某个表的列级别权限。额外的消耗 如果使用查询缓存,在进行读写操作时会带来额外的资源消耗,消耗主要体现在以下几个方面 · 查询的时候会检查是否命中缓存,这个消耗相对较小 · 如果没有命中查询缓存,MYSQL会判断该查询是否可以被缓存,而且系统中还没有对应的缓存,则会将其结果写入查询缓存 · 如果一个表被更改了,那么使用那个表的所有缓冲查询将不再有效,并且从缓冲区中移出。这包括那些映射到改变了的表的使用MERGE表的查询。一个表可以被许多类型的语句更改,例如INSERT、UPDATE、DELETE、TRUNCATE、ALTER TABLE、DROP TABLE或DROP DATABASE。 对于InnoDB而言,事物的一些特性还会限制查询缓存的使用。当在事物A中修改了B表时,因为在事物提交之前,对B表的修改对其他的事物而言是不可见的。为了保证缓存结果的正确性,InnoDB采取的措施让所有涉及到该B表的查询在事物A提交之前是不可缓存的。如果A事物长时间运行,会严重影响查询缓存的命中率 查询缓存的空间不要设置的太大。 因为查询缓存是靠一个全局锁操作保护的,如果查询缓存配置的内存比较大且里面存放了大量的查询结果,当查询缓存失效的时候,会长时间的持有这个全局锁。因为查询缓存的命中检测操作以及缓存失效检测也都依赖这个全局锁,所以可能会导致系统僵死的情况静态表速度更快定长类型和变长类型 CHAR(M)定义的列的长度为固定的,M取值可以为0~255之间,当保存CHAR值时,在它们的右边填充空格以达到指定的长度。当检索到CHAR值时,尾部的空格被删除掉。在存储或检索过程中不进行大小写转换。CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去10个字节的空间,不足的自动用空格填充。 VARCHAR(M)定义的列的长度为可变长字符串,M取值可以为0~65535之间,(VARCHAR的最大有效长度由最大行大小和使用的字符集确定。整体最大长度是65,532字节)。VARCHAR值保存时只保存需要的字符数,另加一个字节来记录长度(如果列声明的长度超过255,则使用两个字节)。VARCHAR值保存时不进行填充。当值保存和检索时尾部的空格仍保留,符合标准SQL。varchar存储变长数据,但存储效率没有CHAR高。 如果一个字段可能的值是不固定长度的,我们只知道它不可能超过10个字符,把它定义为 VARCHAR(10)是最合算的。VARCHAR类型的实际长度是它的值的实际长度+1。空间上考虑,用varchar合适;从效率上考虑,用char合适,关键是根据实际情况找到权衡点。VARCHAR和TEXT、BlOB类型 VARCHAR,BLOB和TEXT类型是变长类型,对于其存储需求取决于列值的实际长度(在前面的表格中用L表示),而不是取决于类型的最大可能尺寸。 BLOB和TEXT类型需要1,2,3或4个字节来记录列值的长度,这取决于类型的最大可能长度。VARCHAR需要定义大小,有65535字节的最大限制;TEXT则不需要。如果你把一个超过列类型最大长度的值赋给一个BLOB或TEXT列,值被截断以适合它。 一个BLOB是一个能保存可变数量的数据的二进制的大对象。4个BLOB类型TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB仅仅在他们能保存值的最大长度方面有所不同。 BLOB 可以储存图片,TEXT不行,TEXT只能储存纯文本文件。 在BLOB和TEXT类型之间的唯一差别是对BLOB值的排序和比较以大小写敏感方式执行,而对TEXT值是大小写不敏感的。换句话说,一个TEXT是一个大小写不敏感的BLOB。 效率来说基本是char>varchar>text,但是如果使用的是Innodb引擎的话,推荐使用varchar代替char char和varchar可以有默认值,text不能指定默认值静态表和动态表 静态表字段长度固定,自动填充,读写速度很快,便于缓存和修复,但比较占硬盘,动态表是字段长度不固定,节省硬盘,但更复杂,容易产生碎片,速度慢,出问题后不容易重建。当只需要一条数据的时候,使用limit 1 表记录中的一行尽量不要超过一个IO单元 区分in和exist select * from 表A where id in (select id from 表B)这句相当于select from 表A where exists(select from 表B where 表B.id=表A.id)对于表A的每一条数据,都执行select * from 表B where 表B.id=表A.id的存在性判断,如果表B中存在表A当前行相同的id,则exists为真,该行显示,否则不显示 区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询。 所以IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况复杂多表尽量少用join MySQL 的优势在于简单,但这在某些方面其实也是其劣势。MySQL 优化器效率高,但是由于其统计信息的量有限,优化器工作过程出现偏差的可能性也就更多。对于复杂的多表 Join,一方面由于其优化器受限,再者在 Join 这方面所下的功夫还不够,所以性能表现离 Oracle 等关系型数据库前辈还是有一定距离。但如果是简单的单表查询,这一差距就会极小甚至在有些场景下要优于这些数据库前辈。尽量用join代替子查询 虽然 Join 性能并不佳,但是和 MySQL 的子查询比起来还是有非常大的性能优势。 MySQL需要为内层查询语句的查询结果建立一个临时表。然后外层查询语句在临时表中查询记录。查询完毕后,MySQL需要插销这些临时表。所以在MySQL中可以使用连接查询来代替子查询。连接查询不需要建立临时表,其速度比子查询要快。尽量少排序 排序操作会消耗较多的 CPU 资源,所以减少排序可以在缓存命中率高等 IO 能力足够的场景下会较大影响 SQL 的响应时间。 对于MySQL来说,减少排序有多种办法,比如: 上面误区中提到的通过利用索引来排序的方式进行优化 减少参与排序的记录条数 非必要不对数据进行排序尽量避免select * 大多数关系型数据库都是按照行(row)的方式存储,而数据存取操作都是以一个固定大小的IO单元(被称作 block 或者 page)为单位,一般为4KB,8KB… 大多数时候,每个IO单元中存储了多行,每行都是存储了该行的所有字段(lob等特殊类型字段除外)。 所以,我们是取一个字段还是多个字段,实际上数据库在表中需要访问的数据量其实是一样的。 也有例外情况,那就是我们的这个查询在索引中就可以完成,也就是说当只取 a,b两个字段的时候,不需要回表,而c这个字段不在使用的索引中,需要回表取得其数据。在这样的情况下,二者的IO量会有较大差异。尽量少or 当 where 子句中存在多个条件以“或”并存的时候,MySQL 的优化器并没有很好的解决其执行计划优化问题,再加上 MySQL 特有的 SQL 与 Storage 分层架构方式,造成了其性能比较低下,很多时候使用 union all 或者是union(必要的时候)的方式来代替“or”会得到更好的效果。尽量用 union all 代替 union union 和 union all 的差异主要是前者需要将两个(或者多个)结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的 CPU 运算,加大资源消耗及延迟。所以当我们可以确认不可能出现重复结果集或者不在乎重复结果集的时候,尽量使用 union all 而不是 union。尽量早过滤 在 SQL 编写中同样可以使用这一原则来优化一些 Join 的 SQL。比如我们在多个表进行分页数据查询的时候,我们最好是能够在一个表上先过滤好数据分好页,然后再用分好页的结果集与另外的表 Join,这样可以尽可能多的减少不必要的 IO 操作,大大节省 IO 操作所消耗的时间。避免类型转换 这里所说的“类型转换”是指 where 子句中出现 column 字段的类型和传入的参数类型不一致的时候发生的类型转换: 人为在column_name 上通过转换函数进行转换直接导致 MySQL(实际上其他数据库也会有同样的问题)无法使用索引,如果非要转换,应该在传入的参数上进行转换,由数据库自己进行转换, 如果我们传入的数据类型和字段类型不一致,同时我们又没有做任何类型转换处理,MySQL 可能会自己对我们的数据进行类型转换操作,也可能不进行处理而交由存储引擎去处理,这样一来,就会出现索引无法使用的情况而造成执行计划问题。优先优化高并发的 SQL,而不是执行频率低某些“大”SQL 对于破坏性来说,高并发的 SQL 总是会比低频率的来得大,因为高并发的 SQL 一旦出现问题,甚至不会给我们任何喘息的机会就会将系统压跨。而对于一些虽然需要消耗大量 IO 而且响应很慢的 SQL,由于频率低,即使遇到,最多就是让整个系统响应慢一点,但至少可能撑一会儿,让我们有缓冲的机会。从全局出发优化,而不是片面调整 尤其是在通过调整索引优化 SQL 的执行计划的时候,千万不能顾此失彼,因小失大。尽可能对每一条运行在数据库中的SQL进行 explain 知道 SQL 的执行计划才能判断是否有优化余地,才能判断是否存在执行计划问题。在对数据库中运行的 SQL 进行了一段时间的优化之后,很明显的问题 SQL 可能已经很少了,大多都需要去发掘,这时候就需要进行大量的 explain 操作收集执行计划,并判断是否需要进行优化。尽量避免where子句中对字段进行null值的判断 会导致引擎放弃索引,进而进行全表扫描。 尽量不要给数据库留null值,尽可能地使用not null填充数据库。可以为每个null型的字段设置一个和null对应的实际内容表述。避免在where中使用!=, >, <操作符 否则引擎放弃使用索引,进行全表扫描。常用查询字段建索引避免在where中使用or imagein和not in关键词慎用,容易导致全表扫面 对连续的数值尽量用between通配符查询也容易导致全表扫描避免在where子句中使用局部变量 sql只有在运行时才解析局部变量。而优化程序必须在编译时访问执行计划,这时并不知道变量值,所以无法作为索引的输入项。 image避免在where子句中对字段进行表达式操作 会导致引擎放弃使用索引 image避免在where子句中对字段进行函数操作 image不要where子句的‘=’左边进行函数、算术运算或其他表达式运算 系统可能无法正确使用索引避免update全部字段 只update需要的字段。频繁调用会引起明显的性能消耗,同时带来大量日志。索引不是越多越好 一个表的索引数最好不要超过6个尽量使用数字型字段而非字符型 因为处理查询和连接时会逐个比较字符串的每个字符,而对于数字型而言只需要比较一次就够了。尽可能用varchar/nvarchar代替char/nchar 变长字段存储空间小,对于查询来说,在一个相对较小的字段内搜索效率更高。。。?避免频繁创建和删除临时表,减少系统表资源消耗select into和create table 新建临时表时,如果一次性插入数据量很大,使用select into代替create table,避免造成大量log,以提高速度。 如果数据量不大,为了缓和系统表的资源,先create table,再insert。 拆分大的DELETE和INSERT语句 因为这两个操作是会锁表的,对于高访问量的站点来说,锁表时间内积累的访问数、数据库连接、打开的文件数等等,可能不仅仅让WEB服务崩溃,还会让整台服务器马上挂了。 所以,一定要拆分,使用LIMIT条件休眠一段时间,批量处理。
wangccsy 2019-12-02 01:50:30 0 浏览量 回答数 0

问题

Android Socket编程学习笔记?报错

      度娘给出的描述: 通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种...
爱吃鱼的程序员 2020-06-22 19:57:11 0 浏览量 回答数 1

回答

在HBase中,大部分的操作都是在RegionServer完成的,Client端想要插入,删除,查询数据都需要先找到相应的RegionServer。什么叫相应的RegionServer?就是管理你要操作的那个Region的RegionServer。Client本身并不知道哪个RegionServer管理哪个Region,那么它是如何找到相应的RegionServer的?本文就是在研究源码的基础上揭秘这个过程。 在前面的文章“HBase存储架构”中我们已经讨论了HBase基本的存储架构。在此基础上我们引入两个特殊的概念:-ROOT-和.META.。这是什么?它们是HBase的两张内置表,从存储结构和操作方法的角度来说,它们和其他HBase的表没有任何区别,你可以认为这就是两张普通的表,对于普通表的操作对它们都适用。它们与众不同的地方是HBase用它们来存贮一个重要的系统信息——Region的分布情况以及每个Region的详细信息。 好了,既然我们前面说到-ROOT-和.META.可以被看作是两张普通的表,那么它们和其他表一样就应该有自己的表结构。没错,它们有自己的表结构,并且这两张表的表结构是相同的,在分析源码之后我将这个表结构大致的画了出来: -ROOT-和.META.表结构 我们来仔细分析一下这个结构,每条Row记录了一个Region的信息。 首先是RowKey,RowKey由三部分组成:TableName, StartKey 和 TimeStamp。RowKey存储的内容我们又称之为Region的Name。哦,还记得吗?我们在前面的文章中提到的,用来存放Region的文件夹的名字是RegionName的Hash值,因为RegionName可能包含某些非法字符。现在你应该知道为什么RegionName会包含非法字符了吧,因为StartKey是被允许包含任何值的。将组成RowKey的三个部分用逗号连接就构成了整个RowKey,这里TimeStamp使用十进制的数字字符串来表示的。这里有一个RowKey的例子: Java代码 Table1,RK10000,12345678 然后是表中最主要的Family:info,info里面包含三个Column:regioninfo, server, serverstartcode。其中regioninfo就是Region的详细信息,包括StartKey, EndKey 以及每个Family的信息等等。server存储的就是管理这个Region的RegionServer的地址。 所以当Region被拆分、合并或者重新分配的时候,都需要来修改这张表的内容。 到目前为止我们已经学习了必须的背景知识,下面我们要正式开始介绍Client端寻找RegionServer的整个过程。我打算用一个假想的例子来学习这个过程,因此我先构建了假想的-ROOT-表和.META.表。 我们先来看.META.表,假设HBase中只有两张用户表:Table1和Table2,Table1非常大,被划分成了很多Region,因此在.META.表中有很多条Row用来记录这些Region。而Table2很小,只是被划分成了两个Region,因此在.META.中只有两条Row用来记录。这个表的内容看上去是这个样子的: .META.行记录结构 现在假设我们要从Table2里面插寻一条RowKey是RK10000的数据。那么我们应该遵循以下步骤: 1. 从.META.表里面查询哪个Region包含这条数据。 2. 获取管理这个Region的RegionServer地址。 3. 连接这个RegionServer, 查到这条数据。 好,我们先来第一步。问题是.META.也是一张普通的表,我们需要先知道哪个RegionServer管理了.META.表,怎么办?有一个方法,我们把管理.META.表的RegionServer的地址放到ZooKeeper上面不久行了,这样大家都知道了谁在管理.META.。 貌似问题解决了,但对于这个例子我们遇到了一个新问题。因为Table1实在太大了,它的Region实在太多了,.META.为了存储这些Region信息,花费了大量的空间,自己也需要划分成多个Region。这就意味着可能有多个RegionServer在管理.META.。怎么办?在ZooKeeper里面存储所有管理.META.的RegionServer地址让Client自己去遍历?HBase并不是这么做的。 HBase的做法是用另外一个表来记录.META.的Region信息,就和.META.记录用户表的Region信息一模一样。这个表就是-ROOT-表。这也解释了为什么-ROOT-和.META.拥有相同的表结构,因为他们的原理是一模一样的。 假设.META.表被分成了两个Region,那么-ROOT-的内容看上去大概是这个样子的: -ROOT-行记录结构 这么一来Client端就需要先去访问-ROOT-表。所以需要知道管理-ROOT-表的RegionServer的地址。这个地址被存在ZooKeeper中。默认的路径是: Java代码 /hbase/root-region-server 等等,如果-ROOT-表太大了,要被分成多个Region怎么办?嘿嘿,HBase认为-ROOT-表不会大到那个程度,因此-ROOT-只会有一个Region,这个Region的信息也是被存在HBase内部的。 现在让我们从头来过,我们要查询Table2中RowKey是RK10000的数据。整个路由过程的主要代码在org.apache.Hadoop.hbase.client.HConnectionManager.TableServers中: Java代码 private HRegionLocation locateRegion(final byte[] tableName, final byte[] row, boolean useCache) throws IOException { if (tableName == null || tableName.length == 0) { throw new IllegalArgumentException("table name cannot be null or zero length"); } if (Bytes.equals(tableName, ROOT_TABLE_NAME)) { synchronized (rootRegionLock) { // This block guards against two threads trying to find the root // region at the same time. One will go do the find while the // second waits. The second thread will not do find. if (!useCache || rootRegionLocation == null) { this.rootRegionLocation = locateRootRegion(); } return this.rootRegionLocation; } } else if (Bytes.equals(tableName, META_TABLE_NAME)) { return locateRegionInMeta(ROOT_TABLE_NAME, tableName, row, useCache, metaRegionLock); } else { // Region not in the cache – have to go to the meta RS return locateRegionInMeta(META_TABLE_NAME, tableName, row, useCache, userRegionLock); } } 这是一个递归调用的过程: Java代码 获取Table2,RowKey为RK10000的RegionServer => 获取.META.,RowKey为Table2,RK10000, 99999999999999的RegionServer => 获取-ROOT-,RowKey为.META.,Table2,RK10000,99999999999999,99999999999999的RegionServer => 获取-ROOT-的RegionServer => 从ZooKeeper得到-ROOT-的RegionServer => 从-ROOT-表中查到RowKey最接近(小于) .META.,Table2,RK10000,99999999999999,99999999999999的一条Row,并得到.META.的RegionServer => 从.META.表中查到RowKey最接近(小于)Table2,RK10000, 99999999999999的一条Row,并得到Table2的RegionServer => 从Table2中查到RK10000的Row 到此为止Client完成了路由RegionServer的整个过程,在整个过程中使用了添加“99999999999999”后缀并查找最接近(小于)RowKey的方法。对于这个方法大家可以仔细揣摩一下,并不是很难理解。 最后要提醒大家注意两件事情: 1. 在整个路由过程中并没有涉及到MasterServer,也就是说HBase日常的数据操作并不需要MasterServer,不会造成MasterServer的负担。 2. Client端并不会每次数据操作都做这整个路由过程,很多数据都会被Cache起来。至于如何Cache,则不在本文的讨论范围之内。 “答案来源于网络,供您参考”
牧明 2019-12-02 02:15:36 0 浏览量 回答数 0

回答

误删文件后恢复数据 本文档主要以CentOS7操作系统为例,介绍如何使用开源工具Extundelete快速恢复被误删除掉的数据。 前提条件 使用本教程进行操作前,请确保您已经注册了阿里云账号。如还未注册,请先完成账号注册。 背景信息 在日常使用中有时难免会出现数据被误删除的情况,该如何快速、有效地恢复数据呢?在阿里云上恢复数据有多种方式,例如: 通过ECS管理控制台回滚已创建的快照、恢复自定义镜像等方式。 购买多台ECS,实现业务的负载均衡和高可用。详情请参见负载均衡。 使用对象存储OSS,存储静态网页和海量图片、视频等重要数据。详情请参见对象存储 OSS(Object Storage Service)。 在Linux下,基于开源的数据恢复工具有很多,常见的有debugfs、R-Linux、ext3grep、extundelete等,比较常用的有ext3grep和extundelete,这两个工具的恢复原理基本一样,只是extundelete功能更加强大。使用阿里云的云服务器时,如果您不小心误删除数据,并且Linux系统也没有与Windows系统下回收站类似的功能,您可以方便快速安装extundelete工具。 extundelete工具能够利用inode信息结合日志去查询该inode所在的block位置,以此查找和恢复所需的数据。该工具最给力的一点就是支持ext3/ext4双格式分区恢复,基于整个磁盘的恢复功能较为强大。 在数据被误删除后,首先要做的是卸载被删除数据所在的磁盘或磁盘分区。因为将文件删除后,仅仅是将文件的inode结点中的扇区指针清零,实际文件还存储在磁盘上,如果磁盘以读写模式挂载,这些已删除的文件的数据块就可能被操作系统重新分配出去,在这些数据块被新的数据覆盖后,误删除的数据就无法恢复。所以,以只读模式挂载磁盘可以尽量降低数据块中数据被覆盖的风险,提高恢复数据成功的几率。 说明 在实际线上恢复过程中,切勿将extundelete安装到您误删的文件所在硬盘,这样会有一定几率将需要恢复的数据彻底覆盖,切记操作前做好快照备份。 本教程适用的对象是: 磁盘中文件误删除的用户,且未对磁盘进行过写入等操作 网站访问量小、少量ECS实例的用户 需安装的软件及版本:e2fsprogs-devel e2fsprogs gcc-c++ make(编译器等)Extundelete-0.2.4。 说明 extundelete需要libext2fs版本1.39或更高版本来运行,但是对于ext4支持,请确保您有e2fsprogs版本1.41或更新版本(可以通过运行命令dumpe2fs并记录其输出的版本)。 以上版本是写文档时的软件版本。您下载的版本可能与此不同。 操作步骤 使用开源工具Extundelete快速恢复被误删的数据的操作步骤如下: 步骤一:部署extundelete工具 步骤二:使用extundelete模拟数据误删除后恢复的过程 步骤一:部署extundelete工具 运行以下命令,部署extundelete工具: wget http://zy-res.oss-cn-hangzhou.aliyuncs.com/server/extundelete-0.2.4.tar.bz2 yum -y install bzip2 e2fsprogs-devel e2fsprogs gcc-c++ make #安装相关依赖和库 tar -xvjf extundelete-0.2.4.tar.bz2 cd extundelete-0.2.4 #进入程序目录 ./configure #如下图表示安装成功 部署extundelete工具 make && make install 这个时候会出现src目录,该目录下有个extundelete可执行文件以及相应路径,其实默认文件安装路径为usr/local/bin,下面模拟删除后恢复数据的操作就在usr/local/bin目录下进行。 步骤二:使用extundelete模拟数据误删除后恢复的过程 完成以下操作,使用extundelete模拟数据误删除后恢复的过程: 检查ECS现有的磁盘和可用分区,并对/dev/vdb进行分区和格式化。具体操作,请参见格式化和挂载数据盘。 fdisk -l 检查磁盘和分区情况 将分区后的磁盘挂载到/zhuyun目录下,然后在/zhuyun下新建测试文件hello,并写入内容test。 mkdir /zhuyun #新建zhuyun目录 mount /dev/vdb1 /zhuyun #将磁盘挂载到zhuyun目录下 echo test > hello #写入测试文件 记录文件hello的md5值。md5sum命令用于生成和校验删除前和恢复后两个文件的md5值。 md5sum hello 记录文档的md5值 模拟删除hello文件。 rm -rf hello cd ~ fuser -k /zhuyun #结束使用某分区的进程树(确认没有资源占用的话,可以跳过此步) 卸载数据盘。 umount /dev/vdb1 #任何的文件恢复工具,在使用前,均要将要恢复的分区卸载或挂载为只读,防止数据被覆盖使用 使用extundelete工具恢复文件。 extundelete --inode 2 /dev/vdb1 #为查找某i节点中的内容,使用2则说明为整个分区搜索,如果需要进入目录搜索,只须要指定目录I节点即可。这是可以看到删除的文件名和inode 恢复文件 /usr/local/bin/extundelete --restore-inode 12 /dev/vdb1 #恢复删除的文件 这个时候会在执行命令的同级目录下出现RECOVERED_FILES目录。 生成恢复后的文件 通过md5sum命令查看恢复后RECOVERED_FILES文件的md5值。 md5sum RECOVERED_FILES 查看删除前的hello和恢复后的RECOVERED_FILES两个文件的md5值是否一致,如果一致,则数据恢复成功。
1934890530796658 2020-03-25 18:35:05 0 浏览量 回答数 0

回答

回 2楼(zc_0101) 的帖子 您好,       您的问题非常好,SQL SERVER提供了很多关于I/O压力的性能计数器,请选择性能计算器PhysicalDisk(LogicalDisk),根据我们的经验,如下指标的阈值可以帮助你判断IO是否存在压力: 1.  % Disk Time :这个是磁盘时间百分比,这个平均值应该在85%以下 2.  Current Disk Queue Length:未完成磁盘请求数量,这个每个磁盘平均值应该小于2. 3.  Avg. Disk Queue Length:磁盘请求队列的平均长度,这个每个磁盘平均值也应该小于2 4.  Disk Transfers/sec:每次磁盘传输数量,这个每个磁盘的最大值应该小于100 5.  Disk Bytes/sec:每次磁盘传入字节数,这个在普通的磁盘上应该在10M左右 6.  Avg. Disk Sec/Read:从磁盘读取的平均时间,这个平均值应该小于10ms(毫秒) 7.  Avg. Disk Sec/Write:磁盘写入的平均时间,这个平均值也应该小于10ms(毫秒) 以上,请根据自己的磁盘系统判断,比如传统的机械臂磁盘和SSD有所不同。 一般磁盘的优化方向是: 1. 硬件优化:比如使用更合理的RAID阵列,使用更快的磁盘驱动器,添加更多的内存 2. 数据库设置优化:比如创建多个文件和文件组,表的INDEX和数据放到不同的DISK上,将数据库的日志放到单独的物理驱动器,使用分区表 3. 数据库应用优化:包括应用程序的设计,SQL语句的调整,表的设计的合理性,INDEX创建的合理性,涉及的范围很广 希望对您有所帮助,谢谢! ------------------------- 回 3楼(鹰舞) 的帖子 您好,      根据您的描述,由于查询产生了副本REDO LOG延迟,出现了架构锁。我们知道SQL SERVER 2012 AlwaysOn在某些数据库行为上有较多变化。我们先看看架构锁: 架构锁分成两类: 1. SCH-M:架构更改锁,主要发生在数据库SCHEMA的修改上,从你的描述看,没有更改SCHEMA,那么可以排除这个因素 2. SCH-S:架构稳定锁,主要发生在数据库的查询编译等活动 根据你的情况,应该属于SCH-S导致的。查询编译活动主要发生有新增加了INDEX, 更新了统计信息,未参数化的SQL语句等等 对于INDEX和SQL语句方面应,我想应该不会有太多问题。 我们重点关注一下统计信息:SQL SERVER 2012 AG副本的统计信息维护有两种: 1. 主体下发到副本 2. 临时统计信息存储在TEMPDB 对于主体下发的,我们可以设置统计信息的更新行为,自动更新时,可以设置为异步的(自动更新统计信息必须首先打开): USE [master] GO ALTER DATABASE [Test_01]     SET AUTO_UPDATE_STATISTICS_ASYNC ON WITH NO_WAIT GO 这样的话查询优化器不等待统计信息更新完成即编译查询。可以优化一下你的BLOCK。 对于临时统计信息存储在TEMPDB里面也是很重要的,再加上ALWAYSON的副本数据库默认是快照隔离,优化TEMPDB也是必要的,关于优化TEPDB这个我想大部分都知道,这里只是提醒一下。 除了从统计信息本身来解决,在查询过程中,可以降低查询的时间,以尽量减少LOCK的时间和范围,这需要优化你的SQL语句或者应用程序。 以上,希望对您有所帮助。谢谢! ------------------------- 回 4楼(leamonjxl) 的帖子 这是一个关于死锁的问题,为了能够提供帮助一些。请根据下列建议进行: 1.    跟踪死锁 2.    分析死锁链和原因 3.    一些解决办法 关于跟踪死锁,我们首先需要打开1222标记,例如DBCC TRACEON(1222,-1), 他将收集的信息写入到死锁事件发生的服务器上的日志文件中。同时建议打开Profiler的跟踪信息: 如果发生了死锁,需要分析死锁发生的根源在哪里?我们不是很清楚你的具体发生死锁的形态是怎么样的。 关于死锁的实例也多,这里不再举例。 这里只是提出一些可以解决的思路: 1.    减少锁的争用 2.    减少资源的访问数 3.    按照相同的时间顺序访问资源 减少锁的争用,可以从几个方面入手 1.    使用锁提示,比如为查询语句添加WITH (NOLOCK), 但这还取决于你的应用是否允许,大部分分布式的系统都是可以加WITH (NOLOCK), 金融行业可能需要慎重。 2.    调整隔离级别,使用MVCC,我们的数据库默认级别是READ COMMITED. 建议修改为读提交快照隔离级别,这样的话可以尽量读写不阻塞,只不过MVCC的ROW VERSION保存到TEMPDB下面,需要维护好TEMPDB。当然如果你的整个数据库隔离级别可以设置为READUNCOMMINTED,这些就不必了。 减少资源的访问数,可以从如下几个方面入手: 1.    使用聚集索引,非聚集INDEX的叶子页面与堆或者聚集INDEX的数据页面分离。因此,如果对非聚集INDEX 操作的话,会产生两个锁,一个是基本表,一个是非聚集INDEX。而聚集INDEX就不一样,聚集INDEX的叶子页面和表的数据页面相同,他只需要一个LOCK。 2.    查询语句尽量使用覆盖INDEX, 使用全覆盖INDEX,就不需要访问基本表。如果没有全覆盖,还会通过RID或者CLUSTER INDEX访问基本表,这样产生的LOCK可能会与其他SESSION争用。 按照相同的时间顺序访问资源: 确保每个事务按照相同的物理顺序访问资源。两个事务按照相同的物理顺序访问,第一个事务会获得资源上的锁而不会被第二个事务阻塞。第二个事务想获得第一个事务上的LOCK,但被第一个事务阻塞。这样的话就不会导致循环阻塞的情况。 ------------------------- 回 4楼(leamonjxl) 的帖子 两种方式看你的业务怎么应用。这里不仅是分表的问题,还可能存在分库,分服务器的问题。取决与你的架构方案。 物理分表+视图,这是一种典型的冷热数据分离的方案,大致的做法如下: 1.    保留最近3个月的数据为当前表,也即就是我们说的热数据 2.    将其他数据按照某种规则分表,比如按照年或者季度或者月,这部分是相对冷的数据 分表后,涉及到几个问题: 第一问题是,转移数据的过程,一般是晚上业务比较闲来转移,转移按照一定的规则来做,始终保持3个月,这个定时任务本身也很消耗时间 再者,关于查询部分,我想你们的数据库服务器应该通过REPLICATION做了读写分离的吧,主库我觉得压力不会太大,主要是插入或者更新,只读需要做视图来包含全部的数据,但通过UNION ALL所有分表的数据,最后可能还是非常大,在某些情况下,性能不一定好。这个是不是业务上可以解决。比如,对于1年前的历史数据,放在单独的只读上,相对热的数据放在一起,这样压力也会减少。 分区表的话,因为涉及到10亿数据,要有好的分区方案,相对比较简单一点。但对于10亿的大表,始终是个棘手的问题,无论分多少个分区,单个服务器的资源也是有限的。可扩展性方面也存在问题,比如在只读上你没有办法做服务器级别的拆分了。这可能也会造成瓶颈。 现在很多企业都在做分库分表,这些的要解决一些高并发,数据量大的问题。不知是否考虑过类似于中间件的方案,比如阿里巴巴的TDDL类似的方案,如果你有兴趣,可以查询相关资料。 ------------------------- 回 9楼(jiangnii) 的帖子 阿里云数据库不仅提供一个数据库,还提供数据库一种服务。阿里云数据库不仅简化了基础架构的部署,还提供了数据库高可用性架构,备份服务,性能诊断服务,监控服务,专家服务等等,保证用户放心、方便、省心地使用数据库,就像水电一样。以前的运维繁琐的事,全部由阿里云接管,用户只需要关注数据库的使用和具体的业务就好。 关于优化和在云数据库上处理大数据量或复杂的数据操作方面,在云数据库上是一样的,没有什么特别的地方,不过我们的云数据库是使用SSD磁盘,这个比普通的磁盘要快很多,IO上有很大的优势。目前单个实例支持1T的数据量大小。陆续我们会推出更多的服务,比如索引诊断,连接诊断,容量分析,空间诊断等等,这些工作可能是专业的DBA才能完成的,以后我们会提供自动化的服务来为客户创造价值,希望能帮助到客户。 谢谢! ------------------------- 回 12楼(daniellin17) 的帖子 这个问题我不知道是否是两个问题,一个是并行度,另一个是并发,我更多理解是吞吐量,单就并行度而言。 提高并行度需要考虑的因素有: 1.    可用于SQL SERVER的CPU数量 2.    SQL SERVER的版本(32位/64位) 3.    可用内存 4.    执行的查询类型 5.    给定的流中处理的行数 6.    活动的并发连接数量 7.    sys.configurations参数:affinity mask/max server memory (MB)/ max degree of parallelism/ cost threshold for parallelism 以DOP的参数控制并行度为例,设置如下: SELECT * FROM sys.configurations WITH (NOLOCK) WHERE name = 'max degree of parallelism' EXEC sp_configure 'max degree of parallelism',2 RECONFIGURE WITH OVERRIDE 经过测试,DOP设置为2是一个比较适中的状态,特别是OLTP应用。如果设置高了,会产生较多的SUSPEND进程。我们可以观察到资源等待资源类型是:CXPACKET 你可以用下列语句去测试: DBCC SQLPERF('sys.dm_os_wait_stats',CLEAR) SELECT * FROM sys.dm_os_wait_stats WITH (NOLOCK) ORDER BY 2 DESC ,3 DESC 如果是吞吐量的话。优化的范围就很广了。优化是系统性的。硬件配置我们选择的话,大多根据业务量来预估,然后考虑以下: 1.    RAID的划分,RAID1适合存放事务日志文件(顺序写),RAID10/RAID5适合做数据盘,RAID10是条带化并镜像,RAID5条带化并奇偶校验 2.    数据库设置,比如并行度,连接数,BUFFER POOL 3.    数据库文件和日志文件的存放规则,数据库文件的多文件设置规则 4.    TEMPDB的优化原则,这个很重要的 5.    表的设计方面根据业务类型而定 6.    CLUSTERED INDEX和NONCLUSTERED INDEX的设计 7.    阻塞分析 8.    锁和死锁分析 9.    执行计划缓冲分析 10.    存储过程重编译 11.    碎片分析 12.    查询性能分析,这个有很多可以优化的方式,比如OR/UNION/类型转换/列上使用函数等等 我这里列举一个高并发的场景: 比如,我们的订单,比如搞活动的时候,订单刷刷刷地增长,单个实例可能每秒达到很高很高,我们分析到最后最常见的问题是HOT PAGE问题,其等待类型是PAGE LATCH竞争。这个过程可以这么来处理,简单列几点,可以参考很多涉及高并发的案例: 1.    数据库文件和日志文件分开,存放在不同的物理驱动器磁盘上 2.    数据库文件需要与CPU个数形成一定的比例 3.    表设计可以使用HASH来作为表分区 4.    表可以设置无序的KEY/INDEX,比如使用GUID/HASH VALUE来定义PRIMARY KEY CLUSTER INDEX 5.    我们不能将自增列设计为聚集INDEX 这个场景只是针对高并发的插入。对于查询而言,是不适合的。但这些也可能导致大量的页拆分。只是在不同的场景有不同的设计思路。这里抛砖引玉。 ------------------------- 回 13楼(zuijh) 的帖子 ECS上现在有两种磁盘,一种是传统的机械臂磁盘,另一种是SSD,请先诊断你的IO是否出现了问题,本帖中有提到如何判断磁盘出现问题的相关话题,请参考。如果确定IO出现问题,可以尝试使用ECS LOCAL SSD。当然,我们欢迎你使用云数据库的产品,云数据库提供了很多有用的功能,比如高可用性,灵活的备份方案,灵活的弹性方案,实用的监控报警等等。 ------------------------- 回 17楼(豪杰本疯子) 的帖子 我们单个主机或者单个实例的资源总是有限的,因为涉及到很大的数据量,对于存储而言是个瓶颈,我曾使用过SAN和SAS存储,SAN存储的优势确实可以解决数据的灵活扩展,但是SAN也分IPSAN和FIBER SAN,如果IPSAN的话,性能会差一些。即使是FIBER SAN,也不是很好解决性能问题,这不是它的优势,同时,我们所有DB SERVER都连接到SAN上,如果SAN有问题,问题涉及的面就很广。但是SAS毕竟空间也是有限的。最终也会到瓶颈。数据量大,是造成性能问题的直接原因,因为我们不管怎么优化,一旦数据量太大,优化的能力总是有限的,所以这个时候更多从架构上考虑。单个主机单个实例肯定是抗不过来的。 所以现在很多企业在向分布式系统发展,对于数据库而言,其实有很多形式。我们最常见的是读写分离,比如SQL SERVER而言,我们可以通过复制来完成读写分离,SQL SERVER 2012及以后的版本,我们可以使用ALWAYSON来实现读写分离,但这只能解决性能问题,那空间问题怎么解决。我们就涉及到分库分表,这个分库分表跟应用结合得紧密,现在很多公司通过中间件来实现,比如TDDL。但是中间件不是每个公司都可以玩得转的。因此可以将业务垂直拆分,那么DB也可以由此拆分开来。举个简单例子,我们一个典型的电子商务系统,有订单,有促销,有仓库,有配送,有财务,有秒杀,有商品等等,很多公司在初期,都是将这些放在一个主机一个实例上。但是这些到了一定规模或者一定数据量后,就会出现性能和硬件资源问题,这时我们可以将它们独立一部分获完全独立出来。这些都是一些好的方向。希望对你有所帮助。 ------------------------- 回 21楼(dt) 的帖子 问: 求大数据量下mysql存储,优化方案 分区好还是分表好,分的过程中需要考虑事项 mysql高并发读写的一些解决办法 答: 分区:对于应用来说比较简单,改造较少 分表: 应用需较多改造,优点是数据量太大的情况下,分表可以拆分到多个实例上,而分区不可以。 高并发优化,有两个建议: 1.    优化事务逻辑 2.    解决mysql高并发热点,这个可以看看阿里的一个热点补丁: http://www.open-open.com/doc/view/d58cadb4fb68429587634a77f93aa13f ------------------------- 回 23楼(aelven) 的帖子 对于第一个问题.需要看看你的数据库架构是什么样的?比如你的架构具有高可用行?具有读写分离的架构?具有群集的架构.数据库应用是否有较冷门的功能。高并发应该不是什么问题。可扩展性方面需要考虑。阿里云数据库提供了很多优势,比如磁盘是性能超好的SSD,自动转移的高可用性,没有任何单点,自动灵活的备份方案,实用的监控报警,性能监控服务等等,省去DBA很多基础性工作。 你第二个问题,看起来是一个高并发的场景,这种高并发的场景容易出现大量的LOCK甚至死锁,我不是很清楚你的业务,但可以建议一下,首先可以考虑快照隔离级别,实现行多版本控制,让读写不要阻塞。至于写写过程,需要加锁的粒度降低最低,同时这种高并发也容易出现死锁,关于死锁的分析,本帖有提到,请关注。 第三个问题,你用ECS搭建自己的应用也是可以的,RDS数据库提供了很多功能,上面已经讲到了。安全问题一直是我们最看重的问题,肯定有超好的防护的。 ------------------------- 回 26楼(板砖大叔) 的帖子 我曾经整理的关于索引的设计与规范,可以供你参考: ----------------------------------------------------------------------- 索引设计与规范 1.1    使用索引 SQL SERVER没有索引也可以检索数据,只不过检索数据时扫描这个表而异。存储数据的目的,绝大多数都是为了再次使用,而一般数据检索都是带条件的检索,数据查询在数据库操作中会占用较大的比例,提高查询的效率往往意味着整个数据库性能的提升。索引是特定列的有序集合。索引使用B-树结构,最小优化了定位所需要的键值的访问页面量,包含聚集索引和非聚集索引两大类。聚集索引与数据存放在一起,它决定表中数据存储的物理顺序,其叶子节点为数据行。 1.2    聚集索引 1.2.1    关于聚集索引 没聚集索引的表叫堆。堆是一种没有加工的数据,以行标示符作为指向数据存储位置的指针,数据没有顺序。聚集索引的叶子页面和表的数据页面相同,因此表行物理上按照聚集索引列排序,表数据的物理顺序只有一种,所以一个表只有一个聚集索引。 1.2.2    与非聚集索引关系 非聚集索引的一个索引行包含指向表对应行的指针,这个指针称为行定位器,行定位器的值取决于数据页保存为堆还是被聚集。若是堆,行定位器指向的堆中数据行的行号指针,若是聚集索引表,行定位器是聚集索引键值。 1.2.3    设计聚集索引注意事项     首先创建聚集索引     聚集索引上的列需要足够短     一步重建索引,不要使用先DROP再CREATE,可使用DROP_EXISTING     检索一定范围和预先排序数据时使用,因为聚集索引的叶子与数据页面相同,索引顺序也是数据物理顺序,读取数据时,磁头是按照顺序读取,而不是随机定位读取数据。     在频繁更新的列上不要设计聚集索引,他将导致所有的非聚集所有的更新,阻塞非聚集索引的查询     不要使用太长的关键字,因为非聚集索引实际包含了聚集索引值     不要在太多并发度高的顺序插入,这将导致页面分割,设置合理的填充因子是个不错的选择 1.3    非聚集索引 1.3.1    关于非聚集索引 非聚集索引不影响表页面中数据的顺序,其叶子页面和表的数据页面时分离的,需要一个行定位器来导航数据,在将聚集索引时已经有说明,非聚集索引在读取少量数据行时特别有效。非聚集索引所有可以有多个。同时非聚集有很多其他衍生出来的索引类型,比如覆盖索引,过滤索引等。 1.3.2    设计非聚集索引     频繁更新的列,不适合做聚集索引,但可以做非聚集索引     宽关键字,例如很宽的一列或者一组列,不适合做聚集索引的列可作非聚集索引列     检索大量的行不宜做非聚集索引,但是可以使用覆盖索引来消除这种影响 1.3.3    优化书签查找 书签会访问索引之外的数据,在堆表,书签查找会根据RID号去访问数据,若是聚集索引表,一般根据聚集索引去查找。在查询数据时,要分两个部分来完成,增加了读取数据的开销,增加了CPU的压力。在大表中,索引页面和数据页面一般不会临近,若数据只存在磁盘,产生直接随机从磁盘读取,这导致更多的消耗。因此,根据实际需要优化书签查找。解决书签查找有如下方法:     使用聚集索引避免书签查找     使用覆盖索引避免书签查找     使用索引连接避免数据查找 1.4    聚集与非聚集之比较 1.4.1    检索的数据行 一般地,检索数据量大的一般使用聚集索引,因为聚集索引的叶子页面与数据页面在相同。相反,检索少量的数据可能非聚集索引更有利,但注意书签查找消耗资源的力度,不过可考虑覆盖索引解决这个问题。 1.4.2    数据是否排序 如果数据需要预先排序,需要使用聚集索引,若不需要预先排序就那就选择聚集索引。 1.4.3    索引键的宽度 索引键如果太宽,不仅会影响数据查询性能,还影响非聚集索引,因此,若索引键比较小,可以作为聚集索引,如果索引键够大,考虑非聚集索引,如果很大的话,可以用INCLUDE创建覆盖索引。 1.4.4    列更新的频度 列更新频率高的话,应该避免考虑所用非聚集索引,否则可考虑聚集索引。 1.4.5    书签查找开销 如果书签查找开销较大,应该考虑聚集索引,否则可使用非聚集索引,更佳是使用覆盖索引,不过得根据具体的查询语句而看。 1.5    覆盖索引 覆盖索引可显著减少查询的逻辑读次数,使用INCLUDE语句添加列的方式更容易实现,他不仅减小索引中索引列的数据,还可以减少索引键的大小,原因是包含列只保存在索引的叶子级别上,而不是索引的叶子页面。覆盖索引充当一个伪的聚集索引。覆盖索引还能够有效的减少阻塞和死锁的发生,与聚集索引类似,因为聚集索引值发生一次锁,非覆盖索引可能发生两次,一次锁数据,一次锁索引,以确保数据的一致性。覆盖索引相当于数据的一个拷贝,与数据页面隔离,因此也只发生一次锁。 1.6    索引交叉 如果一个表有多个索引,那么可以拥有多个索引来执行一个查询,根据每个索引检索小的结果集,然后就将子结果集做一个交叉,得到满足条件的那些数据行。这种技术可以解决覆盖索引中没有包含的数据。 1.7    索引连接 几乎是跟索引交叉类似,是一个衍生品种。他将覆盖索引应用到交叉索引。如果没有单个覆盖索引查询的索引而多个索引一起覆盖查询,SQL SERVER可以使用索引连接来完全满足查询而不需要查询基础表。 1.8    过滤索引 用来在可能没有好的选择性的一个或者多个列上创建一个高选择性的关键字组。例如在处理NULL问题比较有效,创建索引时,可以像写T-SQL语句一样加个WHERE条件,以排除某部分数据而检索。 1.9    索引视图 索引视图在OLAP系统上可能有胜算,在OLTP会产生过大的开销和不可操作性,比如索引视图要求引用当前数据库的表。索引视图需要绑定基础表的架构,索引视图要求企业版,这些限制导致不可操作性。 1.10    索引设计建议 1.10.1    检查WHERE字句和连接条件列 检查WHERE条件列的可选择性和数据密度,根据条件创建索引。一般地,连接条件上应当考虑创建索引,这个涉及到连接技术,暂时不说明。 1.10.2    使用窄的索引 窄的索引有可减少IO开销,读取更少量的数据页。并且缓存更少的索引页面,减少内存中索引页面的逻辑读取大小。当然,磁盘空间也会相应地减少。 1.10.3    检查列的唯一性 数据分布比较集中的列,种类比较少的列上创建索引的有效性比较差,如果性别只有男女之分,最多还有个UNKNOWN,单独在上面创建索引可能效果不好,但是他们可以为覆盖索引做出贡献。 1.10.4    检查列的数据类型 索引的数据类型是很重要的,在整数类型上创建的索引比在字符类型上创建索引更有效。同一类型,在数据长度较小的类型上创建又比在长度较长的类型上更有效。 1.10.5    考虑列的顺序 对于包含多个列的索引,列顺序很重要。索引键值在索引上的第一上排序,然后在前一列的每个值的下一列做子排序,符合索引的第一列通常为该索引的前沿。同时要考虑列的唯一性,列宽度,列的数据类型来做权衡。 1.10.6    考虑索引的类型 使用索引类型前面已经有较多的介绍,怎么选择已经给出。不再累述。 ------------------------- 回 27楼(板砖大叔) 的帖子 这两种都可以吧。看个人的喜好,不过微软现在的统一风格是下划线,比如表sys.all_columns/sys.tables,然后你再看他的列全是下划线连接,name     /object_id    /principal_id    /schema_id    /parent_object_id      /type    /type_desc    /create_date    /modify_date 我个人的喜好也是喜欢下划线。    
石沫 2019-12-02 01:34:30 0 浏览量 回答数 0

问题

HBase运维基础——元数据逆向修复原理

转载自:http://www.hbase.group/article/9 背景 鉴于上次一篇文章——“云HBase小组成功抢救某公司自建HBase集群,挽救30+T数据”的读者反馈,对HB...
pandacats 2019-12-18 15:08:35 3 浏览量 回答数 0

回答

Re回楼主wb313457d9的帖子 后台设置方法: 1、开启远程附件 2、启用SSL链接,预留功能,即SSL加密传输。如需打开,请注释掉SDK中的定义 3、FTP服务器地址,即阿里云OSS服务器地址,目前公网地址为:oss.aliyuncs.com,如有更改, 4、FTP服务器端口,OSS服务器端口,80 5、FTP账号,即OSS_ACCESS_ID 6、FTP密码,即OSS_ACCESS_KEY 7、被动模式,定时转发功能开关 8、远程附件目录,即BUCKET名称,设定后即不能修改,如必须修改,则需要人工转移文件 9、远程访问URL,即URL/BUCKET,也就是 http://oss.aliyuncs.com/(BUCKET),前面的网址也可以由CNAME解析为你自己的域名 10、超时时间,无意义,SDK中尚无定义 11、测试远程附件,不可用,因为discuz程序的原因,本程序已带有一个简单测试程序,运行成功后删除即可。 12、允许的附件扩展名,允许使用远程附件的扩展名 13、禁止的附件扩展名,禁止使用远程附件的扩展名 14、附件尺寸下限,使用远程附件的最小文件,鉴于aliyun除了基于流量还有基于请求数的计费方式,建议特别小的文件保留在web服务器上。 15、隐藏远程附件真实路径,阿里云提供了防盗链功能,两者只能二选一,打开防盗链就不能隐藏远程附件。如果是普通应用,建议使用防盗链即可,可以有效节省服务器流量,如果使用隐藏真实路径,只能是简单的扩展存储空间,失去了OSS的带宽优势。 ------------------------- Rediscuz附件使用OSS存储完美解决方案wb版提供下载 如果论坛是UTF版的,经过测试可以正常使用,但是建议将所带的文件转换为UTF文件存储。 本程序基于discuz2.5开发,对于其他版本没有测试。 请大家在 数据存储计算版面的讨论贴跟帖 http://bbs.aliyun.com/read.php?tid=120635,这里留给作者发布补充吧。 ------------------------------------------------------------------ 这阿里云论坛限制真麻烦,想发点补充没法编辑,只能跟帖。 ------------------------- Rediscuz附件使用OSS存储完美解决方案wb版提供下载 都可以。 在后台设置第15项,隐藏远程附件真实路径的话就是转到空间,但是这样就不可能开启OSS自带的防盗链功能。 如果不隐藏,请开启OSS自带的防盗链功能,这样就直接在OSS下载 ------------------------- Rediscuz附件使用OSS存储完美解决方案wb版提供下载 经测试,支持图片格式的OSS直接下载,其他扩展名附件暂无法直接下载。 正在开发解决方案,请等待... ------------------------- Rediscuz附件使用OSS存储完美解决方案wb版提供下载 插件包已经更新,下载后覆盖原文件即可。 帖子不能编辑,请大家一直往下看了。 ------------------------- 回7楼ap0121d6h的帖子 能给出演示吗?》 已经完全去除了二次下载功能了,不可能再有二次下载。 楼上是否完整安装了整个插件。 ------------------------- Rediscuz附件使用OSS存储完美解决方案wb版提供下载 不隐藏一定要设为公共读,并且强烈建议打开防盗链功能。 ------------------------- 打开防盗链图示 ------------------------- Rediscuz附件使用OSS存储完美解决方案wb版提供下载 经过测试,discuzX2.5自带的日志,相册,文章(门户)均无隐藏真实附件地址功能,所以 使用签名下载附件仅适用于discuz论坛功能。 如果需要使用论坛之外的其他功能,请关闭隐藏真实附件地址功能,并将bucket设定为公共读且添加防盗链规则。 ------------------------- 回17楼ap6214f2r的帖子 开始最初的方案就是按你的方案做的,后来感觉改动太大,又推倒重来! 为了这么几行的程序,花了几十个小时看DZ的程序。 因为替换了DZ的FTP功能,怕造成DZ运行上的问题,因为DZ不止附件上传一个地方用到FTP,所以两天后才推出测试,又之后才发布. 这正是发布的比你晚的原因. 还有一点,如果上传到OSS失败的话,我的附件会自动留在WEB服务器上成为本地附件,访客是无法察觉的,不受影响。 ------------------------- Rediscuz附件使用OSS存储完美解决方案wb版提供下载 插件包已经更新,修正开启防盗链或者私有读写的论坛会出现编辑帖子时图片无法显示的错误. 感谢网友们. PS:修改的文件越来越多了,少修改discuz文件的初衷可能难以实现了. ------------------------- 回22楼facebig的帖子 请在后台打开生成略缩图功能即可。 如果之前有大量未生成略缩图的附件,且编辑时出错,请联系我,我给你个专门版本。 ------------------------- 回24楼facebig的帖子 主机在国外的话,应该是OSS大图显示更有优势了。 因为略缩图根据dz的办法是,先从OSS读取原图,然后保存到web服务器上,然后生成略缩图,然后传输给用户,然后删除图片。 ------------------------- Rediscuz附件使用OSS存储完美解决方案wb版提供下载 在DISCUZ更新文件出来之前,请修改template\default\common\misc_imgcropper.htm 文件,找到$prefix}/{$_GET['img']} 去掉中间斜杠即可。经检查,不管是本地附件还是远程附件,都会多出一个斜杠。这应该是discuz的一个BUG。 只是,我们普通服务器多一个斜杠能访问,OSS多一个斜杠就不让访问了。 ------------------------- 回33楼ap0121d6h的帖子 非也。 album是空间的图片 forum 是论坛的图片 portal 是门户的图片 略缩图是在图片的后面加后缀thumb。 DZ的机制是从OSS读取图片,然后生成略缩图,然后送给用户,反倒更慢。如果网站开始就生成略缩图的话,幻灯片应该优先调用略缩图的吧。 首页打开理论上不会调用本插件的任何文件,不会导致运行变慢。 ------------------------- 回38楼facebig的帖子 经过检查,这是防盗链造成的。 如果一定要使用裁切功能,要不勾选防盗链的 “不允许Refer为空”,没有其他办法。 如果说一定要解决的话,只能使用私有读写 签名模式,然后修改相应的文件才可以。 ------------------------- 回44楼facebig的帖子 请替换source\include\portalcp\目录下的portalcp_block.php文件,替换前请先备份原文件。 ------------------------- 回48楼facebig的帖子 BLOCK在本地,请检查本地data\attachment\block目录 ------------------------- 回51楼ap0121d6h的帖子 DZ程序某个地方应该有问题,理论上只要没有成功上传到OSS的图片都会直接显示本地的。 ------------------------- 回49楼ardong的帖子 建议不上传除了图片和rar文件到OSS,这样就不会出你这样的情况。 如果一定要实现你的功能,必须由web服务器到OSS上读取文件,然后生成原来的文件,然后发送给用户,势必造成二次下载,浪费带宽和流量。 ------------------------- 回55楼facebig的帖子 没用远程附件当然正常。 DZ会判断是否启用远程附件,是否上传成功远程附件两个条件才会调用远程附件文件。 ------------------------- 回57楼facebig的帖子 办法当然有,只是再改下去,又要改DZ的文件了,改动太多可能会带来未知的不稳定性,还有不便于论坛的版本升级。 鱼与熊掌,不可兼得啊。 ------------------------- 回59楼facebig的帖子 放心保存在OSS上,没问题的。 ------------------------- 回62楼facebig的帖子 新版已发布,删除旧版,恢复文件,然后安装新版。 下载链接不变。 ------------------------- 回49楼ardong的帖子 已经发布可选安装包,你安装后上传的文件扩展名就不会变了,但是文件名还是会改变的。 ------------------------- 回68楼taokun0611的帖子 完全不影响。 就算服务器和OSS服务器断开倒是上传到OSS不成功,附件也会存储在本机作为本地附件,不会对访问者造成任何影响。 ------------------------- 回 70楼(ardong) 的帖子 就目前测试来说,基本上没有问题。 一个论坛不是下载站,不会一直上传大文件。 比如我的论坛最大也就允许1M的附件,特殊板块和人员才有大附件。 关于提示和进度条,目前尚无法实现。这仅仅是对dz功能的补充。 ------------------------- 回 73楼(taokun0611) 的帖子 软件说明里面已经说了,会覆盖四个文件,安装前备份这四个文件就可以了。 你出现的提示应该是略缩图没有上传成功,后台关闭略缩图试试。 ------------------------- 有保存在OSS上的http://test.lh.zj.cn/bbs 文章功能DZ并不完善,楼上给一下演示。另外,dz2.5并没有发现有家园功能。 ------------------------- PHP安装的有问题。因为OSS要使用CURL组件,所以就会报错。 ------------------------- 理论上不需要。如发生错误,请根据实际情况处理。此功能在下载附件的时候,出来的文件名正确就没事,不影响图片附件。 ------------------------- 回 85楼(ioriwong) 的帖子 后台选择有无生成略缩图的?? ------------------------- 回 94楼(ioriwong) 的帖子 你的幻灯片绕过url签名处理了。 为什么不用系统自带的幻灯片功能呢? 或者你后台填写的url地址是oss.php还是直接OSS地址? oss.php就是为了你们绕过签名的应用准备的。 ------------------------- 回 98楼(ap3390i7m) 的帖子 原附件可用手动上传的方式上传到OSS,然后把本地附件地址给换掉。 但是有个问题是,除了显示,其他操作均无法进行。 后台有个附件通,可以上传下载附件,这个转移上去是跟新附件效果一样的。 ------------------------- 200G无法通过附件通转移了,太大,太耗费时间了。下载ossbox,上传到OSS,然后改论坛附件访问地址这块就好了 ------------------------- 回 103楼(html5game) 的帖子 谢谢 当时测试UTF-8时,还没这个页面。 ------------------------- 回 106楼(ap7622o2t) 的帖子 谢谢 觉得用的好,请支持118号,每天可以投五票哦。 ------------------------- 回 108楼(victor7780) 的帖子 http://bbs.aliyun.com/read.php?tid=125181&fpage=2&page=2 第16楼 有问题请反馈。 ------------------------- 回 110楼(victor7780) 的帖子 如果还不行,我记得有人说过可以用瀑布流 这些是环境问题了,靠插件解决不了了 ------------------------- 看看你的curl 支持部支持301 ------------------------- 回 114楼(victor7780) 的帖子 机制不同,首页跟版面图片实现方式不同。 ------------------------- 回 117楼(victor7780) 的帖子 不一定支持的,我用阿里云一键包就是不支持的 ------------------------- 回 119楼(victor7780) 的帖子 改下php.ini 另外,百度下要设置什么 ------------------------- 回 122楼(ms263) 的帖子 经检查,上传正常 演示 http://test.lh.zj.cn/bbs ------------------------- 问题出在1101新版更新,修改了文件,稍后请下载更新文件包。 ------------------------- 回 127楼(layayoudi) 的帖子 DZ云附件discuz2.5 1101版本更新文件,仅适用于discuz!x2.5 1101版本,其他版本勿下! 这里帖子无法编辑,今后有新更新发往插件测试论坛 http://test.lh.zj.cn/bbs ------------------------- 回 128楼(wb3134_57d9) 的帖子 附件上传有误,请大家不要下载楼上的附件,有错误,请到测试论坛下载! http://test.lh.zj.cn/bbs 阿里云的五分钟编辑限制...... ------------------------- 回 133楼(zhongyitrip) 的帖子 UTF请自行转码 这个插件原始代码就是UTF的,发布的时候转的GB ------------------------- 回 135楼(ap3390i7m) 的帖子 不能用。 ------------------------- 回 138楼(houzhipeng620) 的帖子 请按照说明到后台设置参数并开启远程附件。 ------------------------- 后台没配置好,请按照说明配置。 ------------------------- 回 149楼(chinazhang) 的帖子 目前没有明确的解决办法,原因不明。 重新安装下试试了。 ------------------------- 回 151楼(chinazhang) 的帖子 应该是阿里云的环境有问题,只是多试几遍后又会好的。
wb3134_57d9 2019-12-01 23:32:48 0 浏览量 回答数 0

回答

索引索引是提高数据库表访问速度的方法。分为聚集索引和非聚集索引。聚集索引:对正文内容按照一定规则排序的目录。非聚集索引:目录按照一定的顺序排列,正文按照另一种顺序排列,目录与正文之间保持一种映射关系。把数据库索引比作字典查询索引,聚集索引就是按照拼音查找,拼音栏中字的顺序就是查找得到的字的顺序。非聚集索引就像按照偏旁部首查找,同是单人旁查到的字所在的页码可能是杂乱的,没有顺序的。存储结构内存中存储的数据是有限的,当需要在磁盘中进行查找时就涉及到了磁盘的 I/O 操作。当磁盘驱动器执行读/写功能时。盘片装在一个主轴上,并绕主轴高速旋转,当磁道在读/写头(又叫磁头) 下通过时,就可以进行数据的读 / 写了。磁盘读取数据是以盘块(block)为基本单位的。位于同一盘块中的所有数据都能被一次性全部读取出来。而磁盘IO代价主要花费在查找时间Ts上。因此我们应该尽量将相关信息存放在同一盘块,同一磁道中。或者至少放在同一柱面或相邻柱面上,以求在读/写信息时尽量减少磁头来回移动的次数,避免过多的查找时间。索引查找时产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的时间复杂度。树高度越小,I/O次数越少。平衡树的高度过深进行多次磁盘IO,导致查询效率低下,而B树和B+树树中每个结点最多含有m个孩子,所以相对平衡树B树和B+树的高度比较低。B树每个节点都存储key和data,所有节点组成这棵树,并且叶子节点指针为null。B+树只有叶子节点存储data,叶子节点包含了这棵树的所有键值,叶子节点不存储指针。所有非终端节点看成是索引,节点中仅含有其子树根节点最大(或最小)的关键字,不包含查找的有效信息。B+树中所有叶子节点都是通过指针连接在一起。总结:为什么使用B+树?1.文件很大,不可能全部存储在内存中,故要存储到磁盘上2.索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数(为什么使用B-/+Tree,还跟磁盘存取原理有关,具体看下边分析)局部性原理与磁盘预读,预读的长度一般为页(page)的整倍数,(在许多操作系统中,页得大小通常为4k)数据库系统巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样 每个节点只需要一次I/O 就可以完全载入,(由于节点中有两个数组,所以地址连续)。而红黑树这种结构, h 明显要深的多。由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性。为什么B+树比B树更适合做索引?1.B+树磁盘读写代价更低B+的内部结点并没有指向关键字具体信息的指针,即内部节点不存储数据。因此其内部结点相对B 树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。2.B+-tree的查询效率更加稳定由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。在MySQL中,最常用的两个存储引擎是MyISAM和InnoDB,它们对索引的实现方式是不同的。MyISAM data存的是数据地址。索引是索引,数据是数据。InnoDB data存的是数据本身。索引也是数据。原文地址:https://blog.csdn.net/qq_40180411/article/details/81431386
vamcily 2019-12-02 01:50:31 0 浏览量 回答数 0

回答

1.阻塞与同步2.BIO与NIO对比3.NIO简介4.缓冲区Buffer5.通道Channel6.反应堆7.选择器8.NIO源码分析9.AIO1.阻塞与同步1)阻塞(Block)和非租塞(NonBlock):阻塞和非阻塞是进程在访问数据的时候,数据是否准备就绪的一种处理方式,当数据没有准备的时候阻塞:往往需要等待缞冲区中的数据准备好过后才处理其他的事情,否則一直等待在那里。非阻塞:当我们的进程访问我们的数据缓冲区的时候,如果数据没有准备好则直接返回,不会等待。如果数据已经准备好,也直接返回2)同步(Synchronization)和异步(Async)的方式:同步和异步都是基于应用程序私操作系统处理IO事件所采用的方式,比如同步:是应用程序要直接参与IO读写的操作。异步:所有的IO读写交给搡作系统去处理,应用程序只需要等待通知。同步方式在处理IO事件的时候,必须阻塞在某个方法上靣等待我们的IO事件完成(阻塞IO事件或者通过轮询IO事件的方式).对于异步来说,所有的IO读写都交给了搡作系统。这个时候,我们可以去做其他的事情,并不拓要去完成真正的IO搡作,当搡作完成IO后.会给我们的应用程序一个通知同步:阻塞到IO事件,阻塞到read成则write。这个时候我们就完全不能做自己的事情,让读写方法加入到线程里面,然后阻塞线程来实现,对线程的性能开销比较大,参考:https://blog.csdn.net/CharJay_Lin/article/details/812598802.BIO与NIO对比block IO与Non-block IO1)区别IO模型 IO NIO方式 从硬盘到内存 从内存到硬盘通信 面向流(乡村公路) 面向缓存(高速公路,多路复用技术)处理 阻塞IO(多线程) 非阻塞IO(反应堆Reactor)触发 无 选择器(轮询机制)2)面向流与面向缓冲Java NIO和IO之间第一个最大的区别是,IO是面向流的.NIO是面向缓冲区的。Java IO面向流意味着毎次从流中读一个成多个字节,直至读取所有字节,它们没有被缓存在任何地方,此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的教据,需要先将它缓存到一个缓冲区。Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,霱要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数裾。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。3)阻塞与非阻塞Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。4)选择器(Selector)Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择"通道:这些通里已经有可以处理的褕入,或者选择已准备写入的通道。这选怿机制,使得一个单独的线程很容易来管理多个通道。5)NIO和BIO读取文件BIO读取文件:链接BIO从一个阻塞的流中一行一行的读取数据image | left | 469x426NIO读取文件:链接通道是数据的载体,buffer是存储数据的地方,线程每次从buffer检查数据通知给通道image | left | 559x3946)处理数据的线程数NIO:一个线程管理多个连接BIO:一个线程管理一个连接3.NIO简介在Java1.4之前的I/O系统中,提供的都是面向流的I/O系统,系统一次一个字节地处理数据,一个输入流产生一个字节的数据,一个输出流消费一个字节的数据,面向流的I/O速度非常慢,而在Java 1.4中推出了NIO,这是一个面向块的I/O系统,系统以块的方式处理处理,每一个操作在一步中产生或者消费一个数据库,按块处理要比按字节处理数据快的多。在NIO中有几个核心对象需要掌握:缓冲区(Buffer)、通道(Channel)、选择器(Selector)。参考:链接image2.png | center | 851x3834.缓冲区Buffer缓冲区实际上是一个容器对象,更直接的说,其实就是一个数组,在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,它也是写入到缓冲区中的;任何时候访问 NIO 中的数据,都是将它放到缓冲区中。而在面向流I/O系统中,所有数据都是直接写入或者直接将数据读取到Stream对象中。在NIO中,所有的缓冲区类型都继承于抽象类Buffer,最常用的就是ByteBuffer,对于Java中的基本类型,基本都有一个具体Buffer类型与之相对应,它们之间的继承关系如下图所示:image3.png | center | 650x3681)其中的四个属性的含义分别如下:容量(Capacity):缓冲区能够容纳的数据元素的最大数量。这一个容量在缓冲区创建时被设定,并且永远不能改变。上界(Limit):缓冲区的第一个不能被读或写的元素。或者说,缓冲区中现存元素的计数。位置(Position):下一个要被读或写的元素的索引。位置会自动由相应的 get( )和 put( )函数更新。标记(Mark):下一个要被读或写的元素的索引。位置会自动由相应的 get( )和 put( )函数更新。2)Buffer的常见方法如下所示:flip(): 写模式转换成读模式rewind():将 position 重置为 0 ,一般用于重复读。clear() :compact(): 将未读取的数据拷贝到 buffer 的头部位。mark(): reset():mark 可以标记一个位置, reset 可以重置到该位置。Buffer 常见类型: ByteBuffer 、 MappedByteBuffer 、 CharBuffer 、 DoubleBuffer 、 FloatBuffer 、 IntBuffer 、 LongBuffer 、 ShortBuffer 。3)基本操作Buffer基础操作: 链接缓冲区分片,缓冲区分配,直接缓存区,缓存区映射,缓存区只读:链接4)缓冲区存取数据流程存数据时position会++,当停止数据读取的时候调用flip(),此时limit=position,position=0读取数据时position++,一直读取到limitclear() 清空 buffer ,准备再次被写入 (position 变成 0 , limit 变成 capacity) 。5.通道Channel通道是一个对象,通过它可以读取和写入数据,当然了所有数据都通过Buffer对象来处理。我们永远不会将字节直接写入通道中,相反是将数据写入包含一个或者多个字节的缓冲区。同样不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。image4.png | center | 368x191在NIO中,提供了多种通道对象,而所有的通道对象都实现了Channel接口。它们之间的继承关系如下图所示:image5.png | center | 650x5171)使用NIO读取数据在前面我们说过,任何时候读取数据,都不是直接从通道读取,而是从通道读取到缓冲区。所以使用NIO读取数据可以分为下面三个步骤:从FileInputStream获取Channel 创建Buffer 将数据从Channel读取到Buffer中 例子:链接 2)使用NIO写入数据使用NIO写入数据与读取数据的过程类似,同样数据不是直接写入通道,而是写入缓冲区,可以分为下面三个步骤:从FileInputStream获取Channel 创建Buffer 将数据从Channel写入到Buffer中 例子:链接 6.反应堆1)阻塞IO模型在老的IO包中,serverSocket和socket都是阻塞式的,因此一旦有大规模的并发行为,而每一个访问都会开启一个新线程。这时会有大规模的线程上下文切换操作(因为都在等待,所以资源全都被已有的线程吃掉了),这时无论是等待的线程还是正在处理的线程,响应率都会下降,并且会影响新的线程。image6.png | center | 739x3362)NIOJava NIO是在jdk1.4开始使用的,它既可以说成“新IO”,也可以说成非阻塞式I/O。下面是java NIO的工作原理:1.由一个专门的线程来处理所有的IO事件,并负责分发。2.事件驱动机制:事件到的时候触发,而不是同步的去监视事件。3.线程通讯:线程之间通过wait,notify等方式通讯。保证每次上下文切换都是有意义的。减少无谓的线程切换。image7.png | center | 689x251注:每个线程的处理流程大概都是读取数据,解码,计算处理,编码,发送响应。7.选择器传统的 server / client 模式会基于 TPR ( Thread per Request ) .服务器会为每个客户端请求建立一个线程.由该线程单独负贵处理一个客户请求。这种模式带未的一个问题就是线程数是的剧增.大量的线程会增大服务器的开销,大多数的实现为了避免这个问题,都采用了线程池模型,并设置线程池线程的最大数量,这又带来了新的问题,如果线程池中有 200 个线程,而有 200 个用户都在进行大文件下载,会导致第 201 个用户的请求无法及时处理,即便第 201 个用户只想请求一个几 KB 大小的页面。传统的 Sorvor / Client 模式如下围所示:image8.png | center | 597x286NIO 中非阻塞IO采用了基于Reactor模式的工作方式,IO调用不会被阻塞,相反是注册感兴趣的特点IO事件,如可读数据到达,新的套接字等等,在发生持定率件时,系统再通知我们。 NlO中实现非阻塞IO的核心设计Selector,Selector就是注册各种IO事件的地方,而且当那些事件发生时,就是这个对象告诉我们所发生的事件。image9.png | center | 462x408当有读或者写等任何注册的事件发生时,可以从Selector中获得相应的SelectionKey,同时从SelectionKey中可以找到发生的事件和该事件所发生的具体的SelectableChannel,以获得客户端发送过来的数据。使用NIO中非阻塞IO编写服务器处理程序,有三个步骤1.向Selector对象注册感兴趣的事件2.从Selector中获取感兴趣的事件3.根据不同事件进行相应的处理8.NIO源码分析Selector是NIO的核心epool模型1)SelectorSelector的open()方法:链接2)ServerSocketChannelServerSocketChannel.open() 链接9.AIOAsynchronous IO异步非阻塞IOBIO ServerSocketNIO ServerSocketChannelAIO AsynchronousServerSocketChannel
wangccsy 2019-12-02 01:46:51 0 浏览量 回答数 0

云产品推荐

上海奇点人才服务相关的云产品 小程序定制 上海微企信息技术相关的云产品 国内短信套餐包 ECS云服务器安全配置相关的云产品 开发者问答 阿里云建站 自然场景识别相关的云产品 万网 小程序开发制作 视频内容分析 视频集锦 代理记账服务 阿里云AIoT