辰迅云帮助中心

其他类

这篇文章给大家介绍.NET中异步编程的原理是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。为什么需要异步编程       既然同步的写法更自然简单,异步的代码(传统的)不好写,还容易出错,那我们为什么需要去编写异步的代码呢?微软还要费这么大劲投入对Async CTP的开发呢?这其中肯定有一些原因。快速响应的用户界面       作为电脑的资深用户,我们肯定有多次“漏斗式鼠标”,“转圈式鼠标”的体验吧。点击一个按钮,然后鼠标就在那儿不停的转圈,再在界面上点两下,界面变灰,标题栏上出现“没有响应”。然后我们束手无策,性子好点的就在那儿等待一会儿,看看能不能恢复过来;性子不好的就打开任务管理器杀掉进程,杀掉进程容易,但有可能会破坏重要数据。那造成这种情况到底是什么原因呢?概括成一句话就是:耗时的操作阻塞了UI线程,造成UI线程不能响应用户操作。关于更底层的原因请移步我的这篇文章:WinForm二三事(一)消息循环。那么这个时候我们就需要一种机制,在发起耗时操作的请求之后要立即返回,不要阻塞UI线程,让UI线程可以继续响应用用户的操作。然后等耗时操作返回后,通过回调来处理耗时操作返回的结果。下面是在UI上使用同步的方式和异步的方式的示意图:更高的伸缩性       对于服务器端应用来说,一般都是一个线程处理一个请求。另外一点是,线程的创建和销毁是昂贵的(这一点可以参考《CLR via C#》中Thread Baisc一章的描述),而服务器的资源肯定是有限的;并且,线程创建的越多,线程上下文切换就会变得越频繁。所以,为了创建高可伸缩性的服务,我们必须用最少的线程处理更多的请求,这样不仅能够做到消耗更少的资源(创建更少的线程),而且在应对请求突发增长的情况也很有用处,那么这里非常重要的一点就是不要阻塞线程,让线程池能够高效的工作。而且,在服务端应用中,有非常多的IO操作:数据库访问,磁盘操作,Socket访问等。对于这些IO操作,不属于计算密集型操作,是不需要单独分配一个线程来处理的。要做到高可伸缩性,异步是一剂良药。假设现在这是一个web应用,当用户的HTTP request到来时,线程池提供一个线程来处理(忽略前面的排队等过程),然后到某一点,我们肯定需要读取磁盘、访问数据库,这个时候我们使用异步的方式,发起IO请求,然后处理HTTP request的线程就可以返回到线程池了,它可以继续处理其他请求,不需要在这里等待IO操作的返回。当IO操作完成之后,会通过回调(具体实现方式请参照后续文章)完成刚才那个HTTP reqeust后续的处理。下面是使用同步方式和异步方式的示意图:上图只画出了一个请求,高亮显示的那一段其实是不需要占用线程的,其实这段时间该线程可以返回线程池,然后分配去做其他请求,而数据库返回结果之后,再从线程池里分配一个线程来处理后续操作。这样,如果请求多的话,线程池就会创建更多的线程来处理请求,***结果大家应该都知道了。从上图可以看出,开始的时候来自线程池的thread1处理请求,然后发起对数据库的请求,发起操作完毕后,thread1被线程池回收;当数据库将结果返回时线程池选择另外一个线程thread2(有可能是原来的那个线程,如果空闲的话)来处理数据库返回的结果,完成后续的操作。对于IO操作非常多的服务来说,所获得的益处是不可估量的。关于.NET中异步编程的原理是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。...

C+与C语言有什么关系

2021/6/12 21:51:04

这篇文章给大家介绍C+与C语言有什么关系,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。错误1: 没有明确的结束方法几乎可以完全肯定地说,对于大多数C++编程人员而言,C#与C++***的不同之处就在于碎片收集。这也意味着编程人员再也无需担心内存泄露和确保删除所有没有用的指针。但我们再也无法准确地控制杀死无用的对象这个过程。事实上,在C#中没有明确的destructor.假如使用非可治理性资源,在不使用这些资源后,必须明确地释放它。对资源的隐性控制是由Finalize方法(也被称为finalizer)提供的,当对象被销毁时,它就会被碎片收集程序调用收回对象所占用的资源。finalizer该当只释放被销毁对象占用的非可治理性资源,而不应牵涉到其他对象。详细介绍C++编程实例说明阐述C++的编程工具几大重要元素深度剖析C++开发工具种种问题漫谈C++编程的编程技巧与技巧浅析C++程序设计学习与实验系统假如在程序中只使用了可治理性资源,那就无需也不应当执行Finalize方法,只要在非可治理性资源的处理中才会用到Finalize方法。由于finalizer需要占用一定的资源,因此应当只在需要它的方法中执行finalizer.直接调用一个对象的Finalize方法是绝对不答应的(除非是在子类的Finalize中调用基础类的Finalize.),碎片收集程序会主动地调用Finalize.从语法上看,C#中的destructor与C++非常相似,但其实它们是完全不同的。C++语法中的destructor只是定义Finalize方法的捷径。因此,下面的二段代码是有区别的:~MyClass()  { // 需要完成的任务  }  MyClass.Finalize() {// 需要完成的任务  base.Finalize();  }错误2:Finalize和Dispose使用谁?从上面的论述中我们已经很清楚,显性地调用finalizer是不答应的,它只能被碎片收集程序调用。假如期望尽快地释放一些不再使用的数量有限的非可治理性资源(如文件句柄),则该当使用IDisposable界面,这一界面有个Dispose方法,它能够帮你完成这个任务。Dispose是无需等待Finalize被调用而能够释放非可治理性资源的方法。假如已经使用了Dispose方法,则应当阻止碎片收集程序再对相应的对象执行Finalize方法。为此,需要调用静态方法GC.SuppressFinalize,并将相应对象的指针传递给它作为参数,Finalize方法就能调用Dispose方法了。据此,我们能够得到如下的代码:public void Dispose()  {  // 完成清理操作  // 通知GC不要再调用Finalize方法  GC.SuppressFinalize(this);  }  public override void Finalize() {  Dispose(); base.Finalize();  }对于有些对象,可能调用Close方法就更合适(例如,对于文件对象调用Close就比Dispose更合适),可以通过创建一个private属性的Dispose方法和public属性的Close方法,并让Close调用Dispose来实现对某些对象调用Close方法。由于不能确定一定会调用Dispose,而且finalizer的执行也是不确定的(我们无法控制GC会在何时运行),C#提供了一个Using语句来保证Dispose方法会在尽可能早的时间被调用。一般的方法是定义使用哪个对象,然后用括号为这些对象指定一个活动的范围,当碰到最内层的括号时,Dispose方法就会被主动调用,对该对象进行处理。对于有些对象,可能调用Close方法就更合适(例如,对于文件对象调用Close就比Dispose更合适),可以通过创建一个private属性的Dispose方法和public属性的Close方法,并让Close调用Dispose来实现对某些对象调用C++语法方法。关于C+与C语言有什么关系就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。...

微信小程序中怎么实现一个登录页面,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。目录结构:图片资源:name.pngkey.pngloginLog.jpglogin.wxml:<view class="container">   <view class="login-icon">   <image class="login-img" src="../images/loginLog.jpg"></image>   </view>   <view class="login-from">     <!--账号-->   <view class="inputView">   <image class="nameImage" src="../images/name.png"></image>   <label class="loginLab">账号</label>   <input class="inputText" placeholder="请输入账号" bindinput="phoneInput" />   </view>   <view class="line"></view>     <!--密码-->   <view class="inputView">   <image class="keyImage" src="../images/key.png"></image>   <label class="loginLab">密码</label>   <input class="inputText" password="true" placeholder="请输入密码" bindinput="passwordInput" />   </view>     <!--按钮-->   <view class="loginBtnView">   <button class="loginBtn" type="primary" size="{{primarySize}}" loading="{{loading}}" plain="{{plain}}" disabled="{{disabled}}" bindtap="login">登录</button>   </view>   </view> </view>login.wxss:page{   height: 100%;  }   .container {   height: 100%;   display: flex;   flex-direction: column;   padding: 0;   box-sizing: border-box;   background-color: #f2f2f2  }   /*登录图片*/ .login-icon{   flex: none;  } .login-img{   width: 750rpx;  }   /*表单内容*/ .login-from {   margin-top: 20px;   flex: auto;   height:100%;  }   .inputView {   background-color: #fff;   line-height: 44px;  } /*输入框*/ .nameImage, .keyImage {   margin-left: 22px;   width: 14px;   height: 14px  }   .loginLab {   margin: 15px 15px 15px 10px;   color: #545454;   font-size: 14px  } .inputText {   flex: block;   float: right;   text-align: right;   margin-right: 22px;   margin-top: 11px;   color: #cccccc;   font-size: 14px  }   .line {   width: 100%;   height: 1px;   background-color: #cccccc;   margin-top: 1px;  } /*按钮*/ .loginBtnView {   width: 100%;   height: auto;   background-color: #f2f2f2;   margin-top: 0px;   margin-bottom: 0px;   padding-bottom: 0px;  }   .loginBtn {   width: 80%;   margin-top: 35px;  }login.js:Page({   data: {   phone: '',   password:''   },   // 获取输入账号  phoneInput :function (e) {   this.setData({   phone:e.detail.value   })   },   // 获取输入密码  passwordInput :function (e) {   this.setData({   password:e.detail.value   })   },   // 登录  login: function () {   if(this.data.phone.length == 0 || this.data.password.length == 0){   wx.showToast({   title: '用户名和密码不能为空',   icon: 'loading',   duration: 2000   })  }else {   // 这里修改成跳转的页面  wx.showToast({   title: '登录成功',   icon: 'success',   duration: 2000   })   }   }  })看完上述内容,你们掌握微信小程序中怎么实现一个登录页面的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注辰讯云资讯频道,感谢各位的阅读!...

本篇文章给大家分享的是有关C语言编写学生成绩管理系统的实现,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。具体内容如下1.课程设计题目:学生成绩管理系统2.完成的功能要求:(1).主要实现的功能:1---学生输入           2---学生插入                               3---学生查询(按学号)          4---学生删除5---学生输出6---计算每名学生的平均分并输出7---计算每科的平均分并输出8---对学生的平均分排序9---统计每门课程的及格率并输出10---输出各科的补考名单(包括学号、姓名、成绩)11---对学生按学号排序0---退出   附加功能设定用户名为admin,密码为key,程序运行提示输入用户名与密码,如果输入正确,显示菜单,才能开始操作(2).程序清单#include<stdio.h>#include<string.h>#define max 100/*给定结构体数组的最大值*/int size = 0;//全局变量/*显示学生属性的信息*/typedef struct studentInformation{ char student_name[20];/*学生的名字*/   char student_class[20];  int student_number;/*学生的学号*/   float student_eng;  float student_math;  float student_C; }information;void menu(){  printf("\n");  printf("********************************\n");   printf(" 学生成绩管理系统\n");   printf("********************************\n");   printf("**************************************\n");  printf(" 1---学生输入 \n");  printf(" 2---学生插入 \n");  printf(" 3---学生查询 \n");  printf("     4---学生删除 \n");  printf(" 5---学生输出 \n");  printf(" 6---计算每名学生的平均分并输出 \n");  printf(" 7---计算每科的平均分并输出 \n");  printf(" 8---对学生的平均分排序 \n");  printf(" 9---统计每门课程的及格率并输出 \n");  printf(" 10---输出各科的补考名单(包括学号、姓名、成绩) \n");  printf(" 11---对学生按学号排序 \n");   printf(" 0---退出 \n"); }//1---学生输入void add_student(information im[], int geshu){  int i;  int count = size + geshu;    for(i = size; i < count; i++)  {  printf("请录入学生的名字:\n");   scanf("%s",im[i].student_name);  printf("请录入学生的学号:\n");  scanf("%d",&im[i].student_number);    printf("请录入学生的班级:\n");   scanf("%s",im[i].student_class);    printf("请录入学生的英语成绩:\n");   scanf("%f",&im[i].student_eng);    printf("请录入学生的数学成绩:\n");   scanf("%f",&im[i].student_math);    printf("请录入学生的C语言成绩:\n");   scanf("%f",&im[i].student_C);    size++;  }/*end of for*/  }//学生插入(按位置插入)void st_insert(information im[],int index){   int i;  if(index < 1 || index > size + 1){  printf("错误!\n");  return;  }  for(i = size; i > index-1 ; i--)  {  im[i] = im[i - 1];  }  printf("请录入插入学生的名字:\n");   scanf("%s",im[i].student_name);  printf("请录入插入学生的学号:\n");  scanf("%d",&im[i].student_number);    printf("请录入插入学生的班级:\n");   scanf("%s",im[i].student_class);    printf("请录入插入学生的英语成绩:\n");   scanf("%f",&im[i].student_eng);    printf("请录入插入学生的数学成绩:\n");   scanf("%f",&im[i].student_math);    printf("请录入插入学生的C语言成绩:\n");   scanf("%f",&im[i].student_C);  size += 1;   printf("插入成功!\n"); }//3---学生查询void check_oneStudent(information im[], int student_number){  int i,j;    /*是实现学生信息的查询*/ for(i = 0; i < size; i++)  {  if(im[i].student_number == student_number)  {  printf("名字 = %s\t学号 = %d\t班级 = %s\t英语成绩 = %0.2f\t数学成绩 = %0.2f\tC语言成绩 = %0.2f\n\n",  im[i].student_name,im[i].student_number,im[i].student_class,im[i].student_eng,im[i].student_math,im[i].student_C);  return ;  }/*end of if*/ }/*end of for*/     printf("没有该学生的信息!\n"); }//4---学生删除void del_studentinfor(information im[],int student_number){  int i,j;    /*找到给定的编号,并删除对应编号的信息*/ for(i = 0; i < size; i++)  {  /*通过比较找到对应编号,然后删除*/   if(im[i].student_number == student_number)  {  /*通过移动数组元素来删除信息*/   for(j = i; j < size - 1; j++)  {  im[j] = im[j+1];  } /*end of for*/   size--;  printf("删除成功!\n");  return ;  }/*end of if*/   }/*end of for*/     printf("没有该学生\n"); }//5---学生输出void check_student(information im[]){  int i;  if(size == 0){  printf("没有学生信息!");  }  for(i = 0; i < size; i++)  {  printf("名字 = %s\t学号 = %d\t班级 = %s\t\n英语成绩 = %0.2f\t数学成绩 = %0.2f\tC语言成绩 = %0.2f\n\n",  im[i].student_name,im[i].student_number,im[i].student_class,im[i].student_eng,im[i].student_math,im[i].student_C);  }/*end of for*/  }// 计算每名学生的平均分并输出void aveGrade(information im[]){  int i;  float ave = 0;    for(i = 0;i < size;i++)  {  ave = (im[i].student_eng + im[i].student_math + im[i].student_C)/3;  printf("学号%d姓名%s的平均成绩 = %0.2f\n",im[i].student_number,im[i].student_name,ave);  } }//每科的平均分并输出void ev_grade(information im[]){  int i,j = 0;  float sum1 = 0.0,sum2 = 0.0,sum3 = 0.0;    for(i = 0;i < size;i++)  {  sum1 = sum1 + im[i].student_eng;   sum2 = sum2 + im[i].student_math;   sum3 = sum3 + im[i].student_C;  j++;  }  printf("英语平均成绩: %0.2f\n",sum1 / j);  printf("数学平均成绩: %0.2f\n",sum2 / j);  printf("C语言平均成绩: %0.2f\n",sum3 / j);  }//统计每门课程的及格率并输出void evsub_ave(information im[]){  int i,j = 0,count1 = 0,count2 = 0,count3 = 0;    for(i = 0;i < size;i++)  {  if(im[i].student_eng >= 60)  {  count1++;  }  if(im[i].student_math >= 60)  {  count2++;  }  if(im[i].student_C >= 60)  {  count3++;  }  j++;  }  printf("英语及格率为:%0.2f\n",count1 * 100.0 / j);  printf("数学及格率为:%0.2f\n",count2 * 100.0 / j);  printf("C语言及格率为:%0.2f\n",count3 * 100.0 / j); }//输出各科的补考名单void rebuild(information im[]){  int i,flag = 1;    printf("英语补考名单:\n");  for(i = 0;i < size;i++)  {  if(im[i].student_eng < 60)  {  printf("姓名:%s\t",im[i].student_name);  printf("学号:%d\t",im[i].student_number);  printf("英语成绩:%0.2f\n",im[i].student_eng);  flag = 0;  }  }  if(flag == 1){  printf("没有补考的!\n");  }else{  flag = 1;  }  printf("数学补考名单:\n");  for(i = 0;i < size;i++)  {  if(im[i].student_math < 60)  {  printf("姓名:%s\t",im[i].student_name);  printf("学号:%d\t",im[i].student_number);  printf("数学成绩:%0.2f\n",im[i].student_math);  flag = 0;  }  }  if(flag == 1){  printf("没有补考的!\n");  }else{  flag = 1;  }  printf("C语言补考名单:\n");  for(i = 0;i < size;i++)  {  if(im[i].student_C < 60)  {  printf("姓名:%s\t",im[i].student_name);  printf("学号:%d\t",im[i].student_number);  printf("C语言成绩:%0.2f\n",im[i].student_C);  flag = 0;  }   }  if(flag == 1){  printf("没有补考的!\n");  } }//对学生按学号排序(由小到大)void num_sort(information im[]){  int i,j;  information stu_temp;    for(i = 0;i < size;i++)  {  for(j = 0; j<size-1-i; j++)  {  if(im[j].student_number > im[j+1].student_number)  {  stu_temp = im[j];  im[j] = im[j+1];  im[j+1] = stu_temp;  }  }  }  printf("排序后的结果:\n");  for(i = 0;i < size;i++)  {  printf("%d\t",im[i].student_number);  } }//对学生的平均分排序(由大到小)void ave_sort(information im[]){  int i,j;  float ave[size],ave_temp;  information stu_temp;    for(i = 0;i < size;i++)  {  ave[i] = (im[i].student_eng + im[i].student_math + im[i].student_C)/3;  }  for(i = 0;i < size-1;i++)  {  for(j = 0; j<size-1-i; j++)  {  if(ave[j] < ave[j+1])  {  stu_temp = im[j];  im[j] = im[j+1];  im[j+1] = stu_temp;    ave_temp = ave[j];  ave[j] = ave[j+1];  ave[j+1] = ave_temp;  }  }  }  printf("排序后的结果:\n");  for(i = 0;i < size;i++)  {  printf("%0.2f\t",ave[i]);  } }int main(void){   information student[max];  int geshu;  int value = -1;   int student_id,index;  char user[] = "admin\0";  char key[] = "key\0";  char user2[10],key2[10];  printf("请输入用户名:\n");  scanf("%s",&user2);  printf("请输入密码:\n");  scanf("%s",&key2);  if(strcmp(user,user2) !=0 || strcmp(key,key2) !=0)  {  printf("用户名或密码错误!\n");  return;  }  else {  while(value != 0)//按"0"退出操作  {   menu();   printf("请选择所要执行的操作:\n");  scanf("%d",&value);   switch(value)//根据value的值来执行相应的操作  {  case 1://1---学生输入 printf("请输入你要录入学生信息的个数:");   scanf("%d",&geshu);   add_student(student, geshu);   break;  case 2://2---学生插入 printf("请输入插入学生的位置:\n");  scanf("%d",&index);  st_insert(student,index);  break;  case 3://3---学生查询 printf("请输入要查询的学生的学号:");  scanf("%d",&student_id);  check_oneStudent(student,student_id);  break;  case 4://4---学生删除 printf("请输入要删除的学生的学号:");  scanf("%d",&student_id);   del_studentinfor(student,student_id);  break;  case 5://5---学生输出 check_student(student);  break;  case 6://6---计算每名学生的平均分并输出 aveGrade(student);  break;  case 7://7---计算每科的平均分并输出  ev_grade(student);  break;  case 8://8---对学生的平均分排序 ave_sort(student);  break;  case 9://9---统计每门课程的及格率并输出 evsub_ave(student);  break;  case 10://10---输出各科的补考名单(包括学号、姓名、成绩) rebuild(student);  break;  case 11://11---对学生按学号排序  num_sort(student);  break;  case 0://0---退出 printf("退出成功!");  break;  default:  printf("输入信息错误!!");   } /*end of switch*/ }/*end of while*/ }  }以上就是C语言编写学生成绩管理系统的实现,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注辰讯云资讯频道。...

docker中如何运行项目

2021/6/12 21:46:06

docker中如何运行项目,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1、进入存放自己项目war的目录编辑Dockerfile文件vim Dockerfile内容如下:rom registry.docker-cn.com/library/tomcat MAINTAINER heihezi heihezi@foxmail.com COPY myproject.war /usr/local/tomcat/webapps2、build自己的镜像docker build -t myproject:latest .不出意外的会显示build镜像的步骤,最后一行为Successfully built b3f6ac3157ae最后的字符串是镜像id的一部分。此时可以运行docker images查看自己的镜像信息3、运行自己的docker容器docker run -d -p 8888:8080 myproject这里 -d 是后台运行,-p 是指定端口,后面的 8888:8080 是映射宿主机的8888端口到docker的8080端口,这时如果运行成功会打印出一个id4、访问自己的项目查看tomcat是否启动成功192.168.1.178:8888访问项目(加项目名)192.168.1.178:8888/myproject看完上述内容,你们掌握docker中如何运行项目的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注辰讯云资讯频道,感谢各位的阅读!...

这篇文章主要介绍了Linux中有哪些常见的问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1、 文档文档及其不足是今年最大的痛点之一。尽管开源的方式产生了优秀的代码,但是制作高质量文档的重要性在最近才走到了前列。随着越来越多的非技术用户采用 Linux 和开源软件,文档的质量和数量将变得至关重要。如果你想为开源项目做出贡献,但不觉得你有足够的技术来提供代码,那么改进文档是参与的好方法。许多项目甚至将文档保存在其仓库中,因此你可以使用你的贡献来适应版本控制的工作流。2、 软件/库版本不兼容我对此感到惊讶,但软件/库版本不兼容性屡被提及。如果你没有运行某个主流发行版,这个问题似乎更加严重。我个人许多年来没有遇到这个问题,但是越来越多的诸如 AppImage、Flatpak 和 Snaps 等解决方案的采用让我相信可能确实存在这些情况。我有兴趣听到更多关于这个问题的信息。如果你最近遇到过,请在评论中告诉我。3、 UEFI 和安全启动尽管随着更多支持的硬件部署,这个问题在继续得到改善,但许多用户表示仍然存在 UEFI 和/或安全启动secure boot问题。使用开箱即用完全支持 UEFI/安全启动的发行版是最好的解决方案。4、 弃用 32 位许多用户对他们最喜欢的发行版和软件项目中的 32 位支持感到失望。尽管如果 32 位支持是必须的,你仍然有很多选择,但可能会继续支持市场份额和心理份额不断下降的平台的项目越来越少。幸运的是,我们谈论的是开源,所以只要有人关心这个平台,你可能至少有几个选择。5、 X 转发的支持和测试恶化尽管 Linux 的许多长期和资深的用户经常使用 X 转发X-forwarding,并将其视为关键功能,但随着 Linux 变得越来越主流,它看起来很少得到测试和支持,特别是对较新的应用程序。随着 Wayland 网络透明转发的不断发展,情况可能会进一步恶化。对比去年的遗留和改进视频(特别是视频加速器、最新的显卡、专有驱动程序、高效的电源管理)、蓝牙支持、特定 WiFi 芯片和打印机以及电源管理以及挂起/恢复,对许多用户来说仍然是麻烦的。更积极的一点的是,安装、HiDPI 和音频问题比一年前显著降低。Linux 继续取得巨大的进步,而持续的、几乎必然的改进周期将会确保持续数年。然而,与任何复杂的软件一样,总会有问题。感谢你能够认真阅读完这篇文章,希望小编分享的“Linux中有哪些常见的问题”这篇文章对大家有帮助,同时也希望大家多多支持辰讯云,关注辰讯云资讯频道,更多相关知识等着你来学习!...

这篇文章主要为大家展示了“Linux环境下VI/VIM编辑文件时无权限保存怎么办”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Linux环境下VI/VIM编辑文件时无权限保存怎么办”这篇文章吧。在Linux环境下,如果直接使用VI/VIM命令编辑没有修改权限的文件时,保存的时候就会提示用户无法进行保存操作,一般的解决方法只能是关闭文件重新以sudo权限打开该文件编辑后再保存(前提是用户具有sudo权限)。其实,在VI/VIM模式下通过一些简单的命令,就能在不关闭当前文件的情况下达到保存文件的目的。方法一关于%! sudo tee % > /dev/null这条命令的说明如下此命令是把当前文件(即%)作为stdin传给sudo tee命令来执行。方法二 在Linux上工作的朋友很可能遇到过这样一种情况,当你用Vim编辑完一个文件时,运行:wq保存退出,突然蹦出一个错误:E45: 'readonly' option is set (add ! to override)这表明文件是只读的,按照提示,加上!强制保存::w!,结果又一个错误出现:"readonly-file-name" E212: Can't open file for writing文件明明存在,为何提示无法打开?这错误又代表什么呢?查看文档:help E212:For some reason the file you are writing to cannot be created or overwritten.The reason could be that you do not have permission to write in the directoryor the file name is not valid.原来是可能没有权限造成的。此时你才想起,这个文件需要root权限才能编辑,而当前登陆的只是普通用户,在编辑之前你忘了使用sudo来启动Vim,所以才保存失败。于是为了防止修改丢失,你只好先把它保存为另外一个临时文件temp-file-name,然后退出Vim,再运行sudo mv temp-file-name readonly-file-name覆盖原文件。但这样操作过于繁琐。而且如果只是想暂存此文件,还需要接着修改,则希望保留Vim的工作状态,比如编辑历史,buffer状态等等,该怎么办?能不能在不退出Vim的情况下获得root权限来保存这个文件?解决方案答案是可以,执行这样一条命令即可::w !sudo tee %接下来我们来分析这个命令为什么可以工作。首先查看文档:help :w,向下滚动一点可以看到: *:w_c* *:write_c* :[range]w[rite] [++opt] !{cmd} Execute {cmd} with [range] lines as standard input (note the space in front of the '!').  {cmd} is executed like with ":!{cmd}", any '!' is replaced with the previous command |:!|. The default [range] for the ":w" command is the whole buffer (1,$)把这个使用方法对应前面的命令,如下所示::       w               !sudo tee % |       |               |  | :[range]w[rite] [++opt] !{cmd}我们并未指定range,参见帮助文档最下面一行,当range未指定时,默认情况下是整个文件。此外,这里也没有指定opt。Vim中执行外部命令接下来是一个叹号!,它表示其后面部分是外部命令,即sudo tee %。文档中说的很清楚,这和直接执行:!{cmd}是一样的效果。后者的作用是打开shell执行一个命令,比如,运行:!ls,会显示当前工作目录下的所有文件,这非常有用,任何可以在shell中执行的命令都可以在不退出Vim的情况下运行,并且可以将结果读入到Vim中来。试想,如果你要在Vim中插入当前工作路径或者当前工作路径下的所有文件名,你可以运行::r !pwd或:r !ls此时所有的内容便被读入至Vim,而不需要退出Vim,执行命令,然后拷贝粘贴至Vim中。有了它,Vim可以自由的操作shell而无需退出。命令的另一种表示形式再看前面的文档:Execute {cmd} with [range] lines as standard input所以实际上这个:w并未真的保存当前文件,就像执行:w new-file-name时,它将当前文件的内容保存到另外一个new-file-name的文件中,在这里它相当于一个另存为,而不是保存。它将当前文档的内容写到后面cmd的标准输入中,再来执行cmd,所以整个命令可以转换为一个具有相同功能的普通shell命令:$ cat readonly-file-name | sudo tee %这样看起来”正常”些了。其中sudo很好理解,意为切换至root执行后面的命令,tee和%是什么呢?%的意义我们先来看%,执行:help cmdline-special可以看到:In Ex commands, at places where a file name can be used, the followingcharacters have a special meaning. These can also be used in the expressionfunction expand() |expand()|.% Is replaced with the current file name. *:_%* *c_%*在执行外部命令时,%会扩展成当前文件名,所以上述的cmd也就成了sudo tee readonly-file-name。此时整个命令即:$ cat readonly-file-name | sudo tee readonly-file-name注意:在另外一个地方我们也经常用到%,没错,替换。但是那里%的作用不一样,执行:help :%查看文档:Line numbers may be specified with: *:range* *E14* *{address}*{number} an absolute line number...% equal to 1,$ (the entire file) *:%*在替换中,%的意义是代表整个文件,而不是文件名。所以对于命令:%s/old/new/g,它表示的是替换整篇文档中的old为new,而不是把文件名中的old换成new。tee的作用现在只剩一个难点: tee。它究竟有何用?维基百科上对其有一个详细的解释,你也可以查看man page。下面这幅图很形象的展示了tee是如何工作的:ls -l的输出经过管道传给了tee,后者做了两件事,首先拷贝一份数据到文件file.txt,同时再拷贝一份到其标准输出。数据再次经过管道传给less的标准输入,所以它在不影响原有管道的基础上对数据作了一份拷贝并保存到文件中。看上图中间部分,它很像大写的字母T,给数据流动增加了一个分支,tee的名字也由此而来。现在上面的命令就容易理解了,tee将其标准输入中的内容写到了readonly-file-name中,从而达到了更新只读文件的目的。当然这里其实还有另外一半数据:tee的标准输出,但因为后面没有跟其它的命令,所以这份输出相当于被抛弃。当然也可以在后面补上> /dev/null,以显式的丢弃标准输出,但是这对整个操作没有影响,而且会增加输入的字符数,因此只需上述命令即可。命令执行之后运行完上述命令后,会出现下面的提示:W12: Warning: File "readonly-file-name" has changed and the buffer was changed in Vim as wellSee ":help W12" for more info.[O]K, (L)oad File:Vim提示文件更新,询问是确认还是重新加载文件。建议直接输入O,因为这样可以保留Vim的工作状态,比如编辑历史,buffer等,撤消等操作仍然可以继续。而如果选择L,文件会以全新的文件打开,所有的工作状态便丢失了,此时无法执行撤消,buffer中的内容也被清空。更简单的方案:映射上述方式非常完美的解决了文章开始提出的问题,但毕竟命令还是有些长,为了避免每次输入一长串的命令,可以将它映射为一个简单的命令加到.vimrc中:" Allow saving of files as sudo when I forgot to start vim using sudo.cmap w!! w !sudo tee > /dev/null %这样,简单的运行:w!!即可。命令后半部分> /dev/null在前面已经解释过,作用为显式的丢掉标准输出的内容。另一种思路至此,一个比较完美但很tricky的方案已经完成。你可能会问,为什么不用下面这样更常见的命令呢?这不是更容易理解,更简单一些么?:w !sudo cat > %重定向的问题我们来分析一遍,像前面一样,它可以被转换为相同功能的shell命令:$ cat readonly-file-name | sudo cat > %这条命令看起来一点问题没有,可一旦运行,又会出现另外一个错误:/bin/sh: readonly-file-name: Permission deniedshell returned 1这是怎么回事?不是明明加了sudo么,为什么还提示说没有权限?稍安勿躁,原因在于重定向,它是由shell执行的,在一切命令开始之前,shell便会执行重定向操作,所以重定向并未受sudo影响,而当前的shell本身也是以普通用户身份启动,也没有权限写此文件,因此便有了上面的错误。重定向方案这里介绍了几种解决重定向无权限错误的方法,当然除了tee方案以外,还有一种比较方便的方案:以sudo打开一个shell,然后在该具有root权限的shell中执行含重定向的命令,如::w !sudo sh -c 'cat > %'可是这样执行时,由于单引号的存在,所以在Vim中%并不会展开,它被原封不动的传给了shell,而在shell中,一个单独的%相当于nil,所以文件被重定向到了nil,所有内容丢失,保存文件失败。既然是由于%没有展开导致的错误,那么试着将单引号'换成双引号"再试一次::w !sudo sh -c "cat > %"成功!这是因为在将命令传到shell去之前,%已经被扩展为当前的文件名。有关单引号和双引号的区别可以参考这里,简单的说就是单引号会将其内部的内容原封不动的传给命令,但是双引号会展开一些内容,比如变量,转义字符等。当然,也可以像前面一样将它映射为一个简单的命令并添加到.vimrc中:" Allow saving of files as sudo when I forgot to start vim using sudo.cmap w!! w !sudo sh -c "cat > %"注意:这里不再需要把输出重定向到/dev/null中。以上是“Linux环境下VI/VIM编辑文件时无权限保存怎么办”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...

这篇文章主要介绍Linux运维人员需要掌握一门编程语言吗,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! 最近经常有同行的朋友或者Linux初学者问我:运维人员是否需要学一门语言,那么该学哪种语言呢?对于这个问题,我分两个方面回答:首选,在大数据、云计算发展迅猛的今天,系统运维人员如果不懂一点开发语言的话,确实会举步维艰,因为在运维工作中,业务系统的繁多,线上服务器规 模很大时,只能通过写脚本的方式(自动化也是脚本一种哦)自动化完成,不然,如此重复和繁琐的工作,靠人力是无法负担的,所以,学习一门可以让运维工作批 量完成的语言,就显得很重要了。那么应该学习一门什么语言呢?对于Linux系统运维人员来说,答案就比较复杂,因为有很多的选择。shell、perl、python、ruby等等。我认为,每一个Linux系统运维人员都应该知道Linux外壳程序(sh或bash),另外还要知道Perl、Ruby或Python当中的某一门语言。至于学哪一门语言,并不重要。在我看来,任何语言都是为运维工作服务的,只要能完成运维工作,你喜欢哪种语言,那么你就用哪种语言吧,当然,对于初学者会有一些不同的选择,如果 你是初学者,推荐当下比较流行或者企业应用比较多的语言来学的话,对以后的工作会有很大帮助,毕竟没有哪个公司愿意接受一种陌生的语言。那么,是否初学者一开始就要马上学习一门运维语言呢,我觉得这个为时过早了,因为任何语言,特别是shell、python等这些语言,与 Linux联系很紧密,如果对Linux一无所知的时候,就茫然的去学语言,那无异于盲人摸象,所以我建议,学习系统语言,一定要有Linux基础后再去 学习,你会发现,语言也变得容易多了。shell作为一门通用的系统语言,是所有运维人员都必须要了解和掌握的,通过shell能帮助我们解决日常工作中很多重复、繁琐的工作,但是 shell的基础就是系统命令,因此,只有掌握了系统命令的原理和使用方法,shell才能运行起来,我见过很多学Linux的朋友,他们也接触运维多 年,但是对于如何执行for循环、while循环、if with [[或[、$1、$2、$3&hellip; $*和 $@ 以及case语句的使用都不会,他们迟早会为没有尽早学习bash而自责不已。那么又有人问我,我对shell已经非常熟悉了,但还是找不到工作,很多单位都要求会python或ruby等语言,我是否还要学这些语言呢?这个问题分为两个方面,首先从员工角度来讲,企业招聘员工是为自身服务的,交给员工的任务只要能按质保量的完成,其实已经足够了,至于通过什么语言 来实现的,并不重要。可能有些企业出于习惯或传统的目的,强制要求要通过一种语言去完成所有工作,这是企业环境问题。如果每个员工都有完全依赖于企业的这 种习惯,岂不是要学会所有的语言吗,显然,这并不是一种常态。很多朋友都看过招聘信息,对语言的要求基本都是shell、python、perl等任意一个熟悉,那么也就说明对运维工作的语言要求是相对较宽泛 的,我曾就职多家大型公司,对于运维的工作都有专业的任务调度管理平台,而调度管理平台上,可以支持任何语言编写的运维调度任务,因此,你无需为学习哪个 语言而发愁。然后,从职业管理的角度来看,我认为真正擅长其中一门语言,对另外其它语言有所涉猎,这是最大的竞争力,哪怕这意味着仅仅阅读介绍这些语言的书籍的 头几个章节。真正擅长其中一门语言意味着,你深入了解如何运用该语言,深入了解该语言在“底层”是怎么一回事,那样你在设计更大型的程序时,就能作出更合 理的决策。我之所以把这个问题上升到职业管理问题的层面来讨论,原因在于,如果你想受雇于一家使用不同语言的公司,“成为愿意学习不同语言的专家”远比 “成为只想学习大有潜力的语言”或“对这门或那门语言一知半解,但是从来没有耐心把某一门语言学好的人”来得重要。以上是“Linux运维人员需要掌握一门编程语言吗”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注辰讯云资讯频道!...

这篇文章主要介绍了linux中shell脚本编写和运行的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。编写第一个shell脚本在gedit中编写.sh格式的文件,保存为a.sh。 代码:#! /bin/bash # employ bash shellplayer1=xiaoming # define a player1player2=ken echo "Game start! $player1 $player2" # echo is used to printf in terminal在终端调用脚本,定位到目录,然后输入:bash a.sh看到打印结果如上所示。编写第一个if/else脚本编写的if/else如下: if和 ; 之间的代码ls -l a.sh是用来判断当前的目录下是否存在a.sh这个文件。if和else的基本格式如下所示,if command ; then code1 else code2 fi在终端调用的结果如下,可以看到输出了ls return true再看一个if/else脚本如下脚本,if/else格式和上面格式一致,重点看下 if 和 ;间的那个命令,命令开始以 [,后面有4个参数 $1,=,me,]输出的结果如下所示:用 = 来判断输入的字符串是否等于me。其他的常用判断参数见下图:看一个for循环for循环的格式如下脚本所示:#! /bin/bash # employ bash shellfor num in 1 2 3 4 5 sixdo    echo "num=$num"for(( num=1; num<7; num++)) # method2do   echo "num=$num"donewhile循环while循环的基本格式如下:#! /bin/bashi=7 j=10while [ $i -lt $j ] do  echo "num1 = $i, num2=$j"  ((i++))done感谢你能够认真阅读完这篇文章,希望小编分享的“linux中shell脚本编写和运行的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持辰讯云,关注辰讯云资讯频道,更多相关知识等着你来学习!...

这篇文章主要为大家展示了“磁盘慢会导致Linux负载飙升的原因”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“磁盘慢会导致Linux负载飙升的原因”这篇文章吧。 一、CPU利用率和负载率的区别这里要区别CPU负载和CPU利用率,它们是不同的两个概念,但它们的信息可以在同一个top命令中进行显示。CPU利用率显示的是程序在运行期间实时占用的CPU百分比,这是对一个时间段内CPU使用状况的统计,通过这个指标可以看出在某一个时间段内CPU被占用的情况, 如果被占用时间很高,那么就需要考虑CPU是否已经处于超负荷运作。而CPU负载显示的是在一段时间内CPU正在处理以及等待CPU处理的进程数之和的统计信息,也就是CPU使用队列的长度的统计信息。CPU利用率高并不意味着负载就一定大,可能这个任务是一个CPU密集型的。一样CPU低利用率的情况下是否会有高Load Average的情况产生呢?理解占有时间和使用时间就可以知道,当CPU分配时间片以后,是否使用完全取决于使用者,因此完全可能出现低利用率高Load Average的情况。另外IO设备也可能导致CPU负载高。由此来看,仅仅从CPU的使用率来判断CPU是否处于一种超负荷的工作状态还是不够的,必须结合Load Average来全局的看CPU的使用情况。网上有个例子来说明两者的区别如下:某公用电话亭,有一个人在打电话,四个人在等待,每人限定使用电话一分钟,若有人一分钟之内没有打完电话,只能挂掉电话去排队,等待下一轮。电话在这里就相当于CPU,而正在或等待打电话的人就相当于任务数。在电话亭使用过程中,肯定会有人打完电话走掉,有人没有打完电话而选择重新排队,更会有新增的人在这儿排队,这个人数的变化就相当于任务数的增减。为了统计平均负载情况,我们5秒钟统计一次人数,并在第1、5、15分钟的时候对统计情况取平均值,从而形成第1、5、15分钟的平均负载。有的人拿起电话就打,一直打完1分钟,而有的人可能前三十秒在找电话号码,或者在犹豫要不要打,后三十秒才真正在打电话。如果把电话看作CPU,人数看作任务,我们就说前一个人(任务)的CPU利用率高,后一个人(任务)的CPU利用率低。当然, CPU并不会在前三十秒工作,后三十秒歇着,CPU是一直在工作。只是说,有的程序涉及到大量的计算,所以CPU利用率就高,而有的程序牵涉到计算的部分很少,CPU利用率自然就低。但无论CPU的利用率是高是低,跟后面有多少任务在排队没有必然关系。CPU数量和CPU核心数(即内核数)都会影响到CPU负载,因为任务最终是要分配到CPU核心去处理的。两块CPU要比一块CPU好,双核要比单核好。因此,我们需要记住,除去CPU性能上的差异,CPU负载是基于内核数来计算的,即“有多少内核,即有多少负载”,如单核最好不要超过100%,也就是负载为1.00,如此类推。Linux里有一个/proc目录,存放的是当前运行系统的虚拟映射,其中有一个文件为cpuinfo,这个文件里存放着CPU的信息。/proc/cpuinfo文件按逻辑CPU而非真实CPU分段落显示信息,每个逻辑CPU的信息占用一个段落,第一个逻辑CPU标识从0开始。$ cat /proc/cpuinfo processor       : 0vendor_id       : GenuineIntelcpu family      : 6model           : 63model name      : Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHzstepping        : 2microcode       : 0x36cpu MHz         : 2399.998cache size      : 20480 KBphysical id     : 0siblings        : 2core id         : 0cpu cores       : 2apicid          : 0initial apicid  : 0fpu             : yesfpu_exception   : yescpuid level     : 15wp              : yesflags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr ......bogomips        : 4799.99clflush size    : 64cache_alignment : 64address sizes   : 42 bits physical, 48 bits virtualpower management:要理解该文件中的CPU信息,有几个相关的概念要知道,如:processor表示逻辑CPU的标识、model name表示真实CPU的型号信息、physical id表示真实CPU和标识、cpu cores表示真实CPU的内核数等等。逻辑CPU的描述:现在的服务器一般都使用了“超线程”(Hyper-Threading,简称HT)技术来提高CPU的性能。超线程技术是在一颗CPU同时执行多个程序而共同分享一颗CPU内的资源,理论上要像两颗CPU一样在同一时间执行两个线程。虽然采用超线程技术能同时执行两个线程,但它并不象两个真正的CPU那样,每各CPU都具有独立的资源。当两个线程都同时需要某一个资源时,其中一个要暂时停止,并让出资源,直到这些资源闲置后才能继续。因此超线程的性能并不等于两颗CPU的性能。具有超线程技术的CPU还有一些其它方面的限制。二、CPU负载率的计算方式Load average的概念源自UNIX系统,虽然各家的公式不尽相同,但都是用于衡量正在使用CPU的进行数量和正在等待CPU的进程数量,一句话就是runable processes的数量。所以Load average可以作为CPU瓶颈的参考指标,如果大于CPU的数量,说明CPU可能不够用了。但是,在Linux上有点差异!Linux上的load average除了包括正在使用CPU的进程数量和正在等待CPU的进程数量之外,还包括uninterruptible sleep的进程数量。通常等待IO设备、等待网络的时候,进程会处于uninterruptible sleep状态。Linux设计者的逻辑是,uninterruptible sleep应该都是很短暂的,很快就会恢复运行,所以被等同于runnable。然而uninterruptible sleep即使再短暂也是sleep,何况现实世界中uninterruptible sleep未必很短暂,大量的、或长时间的uninterruptible sleep通常意味着IO设备遇到了瓶颈。众所周知,sleep状态的进程是不需要CPU的,即使所有的CPU都空闲,正在sleep的进程也是运行不了的,所以sleep进程的数量绝对不适合用作衡量CPU负载的指标,Linux把uninterruptible sleep进程算进load average的做法直接颠覆了load average的本来意义。所以在Linux系统上,load average这个指标基本失去了作用,因为你不知道它代表什么意思,当看到load average很高的时候,你不知道是runnable进程太多还是uninterruptible sleep进程太多,也就无法判断是CPU不够用还是IO设备有瓶颈。从另一个方面来说,也就可以解释为什么磁盘慢时(大量磁盘使用时),CPU负载会飙高了。基本上我碰到CPU负载高的情况就两种情况:CPU本身处理太多任务,再加上软中断和上下文切换太频繁导致负载高;再就是磁盘太慢导致了不可中断睡眠太多导致CPU负载高。以上是“磁盘慢会导致Linux负载飙升的原因”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...