好吧,开一系列介绍linux进程的文章,先从fork说起。
fork()函数就是复制当前的进程创造一个新的进程,当前的进程叫做叫做父进程,复制产生的进程叫做子进程。
子进程复制父进程的一切资源,除了:
1 子进程具有独一无二的进程 pid,
2 子进程有一个父进程,其ID和创造这个进程(子进程)的id相同
进程调用fork后,内核将控制权交给两个进程。
先看代码,这里有点意思,程序的输出结果如果你不仔细分辨的,真的会让你想不到。
#include<stdio.h>
#include<unistd.h>
int main()
{
pid_t fpid; //表示fork()返回的值
int count = 0;
fpid = fork();
if(fpid < 0)
printf("error in fork!");
else if (fpid == 0){
printf("I am the child process, my process id is %d\n", getpid());
printf("I am son of my father\n");
count ++;
}
else {
printf("I am the parent process, my process id is %d \n", getpid());
printf("I am father of my son\n");
count++;
}
printf(" as a result: %d\n", count);
return 0;
}
结果在我的机子上显示为;
I am the parent process, my process id is 10369
I am father of my son
as a result: 1
root@yubo-2:~/test/unix_linux# I am the child process, my process id is 10370
I am son of my father
as a result: 1
也就是说一个主程序在没有循环的情况下,居然有两个返回值,它是怎么做到的后来剖析,现在简单地分析下导致这种现象的原因.
1 在父进程中,fork返回新创建子进程的进程id
2 在子进程中,fork返回0
3 fork返回一个负值,意味着fork创建失败。
看到网上说,进程经过fork()后形成了进程链,父进程的fpid指向子进程的进程id,因为子进程没有子进程(至少在这个程序中),所以其fpid为0.
fork()出错的原因可能有几下几种:
1 当前的进程数已经达到了系统规定的上限,这是errno的值为EAGAIN.
2 系统内存不足,这时errno的值为ENOMEM
两个进程的执行没有先后顺序,根据调度算法而已.
#include<stdio.h>
int main()
{
int ret_from_fork, mypid;
mypid = getpid();
printf("Before: my pid is %d\n", mypid);
ret_from_fork = fork();
sleep(1);
printf("After, my pid is %d, fork() said %d\n", getpid(), ret_from_fork);
}
结果如下所示:

注意第一段所说,fork调用是将原来的进程复制到新的进程,包括数据和程序,但是,新的程序是运行到当前程序行,并不会从整个程序的开头从头运行。这个图片中,原进程21635运行Before:后运行fork,启动了一个子进程,随后,进程21635接着进行,打印了After:,当进程21635消亡后,才转移到子进程,注意,子进程并不是从头开始的,而是从fork开始,也就是说,fork的Before不会打印,只执行After的语句。
p21636
|------->
Before | After
=========|=======> p21635
fork
一个fork会产生2个进程,两个fork会产生4个进程,依次类推….
#include<stdio.h>
int main()
{
fork();
fork();
fork();
printf("my pid is %d \n", getpid());
}
yubo@debian:~/test/tmp/unix$
结果如下所示:

#include<stdio.h>
int main()
{
int fork_rv;
printf("Before: my pid is %d \n", getpid());
fork_rv = fork();
if (fork_rv == -1)
perror("Fork failed\n");
else if (fork_rv == 0)
printf("I am the child, my pid is %d\n", getpid());
else
printf("I am the parent, my pid is %d\n", getpid());
}

先上代码;
#include<stdio.h>
#include<unistd.h>
int main()
{
int i = 0;
printf("i son/pa ppid pid fpid\n");
/* ppid 是当前进程的父进程pid,
* pid 是当前进程的pid
* fpid 是fork返回给当前进程的值
*/
for(i = 0; i < 2; i++){
pid_t fpid = fork();
if(fpid == 0)
printf(" %d child %4d %4d %4d\n", i, getppid(), getpid(), fpid);
else
printf("%d parent %4d %4d %4d\n", i, getppid(), getpid(), fpid);
}
return 0;
}
这是在我的机子上的结果:
root@yubo-2:~/test/unix_linux# ./test
i son/pa ppid pid fpid
0 parent 11040 11508 11509
1 parent 11040 11508 11510
root@yubo-2:~/test/unix_linux# 1 child 1 11510 0
0 child 1 11509 0
1 parent 1 11509 11511
1 child 1 11511 0
仔细分析这个输入法,在 i = 0时,上面这个程序调用fork函数,系统中出现两个进程 p11508和p11509(p是进程的意思),且p11508是p11509的父进程,p11040是p11508的父进程。因为对应的函数为: getpid(), fpid = fork(), getppod().即进程链p11040->p11508->p11509.
我建议看官方文档,这样效果才能明显.
这个就先不仔细说明了,详情请了解这篇文章
如果出现:”ImportError: No module named django”,请确保使用:
PYTHONPATH=/path/to/django/parent/dir
即可导入了django,关于这个Django包在什么地方,你可以使用 pip命令重新安装交一遍django,这样就可以了,有关PYTHONPATH应该加到用户配置文件中。
django的源代码放在什么地方呢?最好不要放在/root 目录下,因为这样的话会给/root 目录带来风险。
在django的源代码的目录下,键入命令
django-admin startproject mysite
其中,mysite 可以是任何名字,只要你喜欢就成了。这是在该目录下会生成mysite目录,其中的内容如下:
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
其中manage.py激活Django项目
子目录mysite是针对你创建的项目的包,可以导入任何你想要导入的
init.py 告诉python这是针对python的包。
settings.py是针对Django项目的配置文件。
urls.py Django项目的URLS的声明文件,这里面是关于你Django项目的”内容表”
wsgi.py 是WSGI兼容的web服务器,
还要记住一点,python是MVC(model view controler)模型的。 因为本对python不是很熟,所以这块也不是很明白
使用以下命令,
python manage.py runserver
当然,前提实在相应的目录下执行这条命令。然后就冒出一大串文字。其中会有这么一大串
…Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
我的是安在了遥远的VPS上,只能利用lynx去间接访问127.0.0.1:8000,显示了It works,但是怎么能在前台浏览器上查看效果呢?使用下面的命令:
python manage.py runserver 0.0.0.0:8000
然后在你的前段浏览器输入vps的ip:8000,就可以看见It works!再再就是,由于我的项目目录建立在了/root下,导致了Disallow的警告。
有时候并不是上面的原因导致了DisallowedHost,’You may need to add ip to ALLOWED_HOSTS’
你可以将项目里的setting.py中ALLOWED_HOSTS=[‘ip’,’localhost’, ‘127.0.0.1’],设置进去就可以。
这里先说一下项目与应用的关系,在原始文档里项目是project,应用是app,在使用命令的时候你也可以看见这两种的区别,一个项目可以由多个app组成,这就是基本的逻辑关系。按照官网上的说法,你的app可以放在系统的任何位置,为了方便,我建议放在项目的平行目录(与顶层的manage.py平行即可)。
python manage.py startapp polls
会在源目录下产生polls目录,里面包含:
.
├── admin.py
├── apps.py
├── __init__.py
├── __init__.pyc
├── migrations
│ └── __init__.py
├── models.py
├── tests.py
├── urls.py
├── urls.pyc
├── views.py
└── views.pyc
打开polls/views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
HttpResponse 的意思是在页面上打印出这句话,可以简化为print。
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^polls/', include('polls.urls')),
url(r'^admin/', admin.site.urls),
]
这块的知识不太一样了,请看下面哈.新版的django不推荐使用url,改为了path,道理差不多,大家可以看看下面的内容,就应该理解了。
运行程序
python manage.py runserver 0.0.0.0:8000
浏览http://ip:8000/polls 就会看见polls的内容了. url这里是一个函数
在生成mysite的同事,Django会默认生成sqllite3数据库,在mysite/setting.py中DATABASES 字段就是关于数据库的.
这个字段是安装在 项目 下的setting.py文件中,即:只要你修改了 应用的 models.py,在做数据迁移之前,必须让项目的setting.py文件知道你的修改。
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
...
]
注意这些字段,比较关键。后期的应用要注意这些。
这个玩意包含你的数据库构架(databases layout),在这个poll app中,我们将会创建两个models: Question和Choice. 前者有一个question和一个公开的日期;后者有两个域:文本选择域和一个vote tally.每一个Choice 对应一个Question.
在你的项目polls下编辑文件models.py:
from django.db import models
# Create your models here.
class Question(models.Model):
question_text = models.CharField(max_length = 200)
pub_data = models.DateTimeField('data published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete = models.CASCADE)
choice_text = models.CharField(max_length = 200)
votes = models.IntegerField(default=0)
生成:
Migrations for 'polls':
polls/migrations/0001_initial.py:
- Create model Choice
- Create model Question
- Add field question to choice
下面的命令是告诉django返回刚才数据改变时可读的sql文本。
生成:
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL);
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" RENAME TO "polls_choice__old";
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id"
integer NOT NULL REFERENCES "polls_question" ("id"));
INSERT INTO "polls_choice" ("choice_text", "votes", "id", "question_id")
SELECT "choice_text", "votes", "id", NULL FROM "polls_choice__old";
DROP TABLE "polls_choice__old";
CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id");
COMMIT;
python manage.py check
如果在生成数据库的时候有麻烦了,使用这个命令检查一下 makemigrations这句命令只是你告诉Django你做出了一些数据改动,然而使用下面的命令进行存储数据:
python manage.py migrate
migrate命令将INSTALLED_APPS的字段全部用上了. 下面是migrate的输出:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Applying polls.0001_initial... OK
After Playing with the API: in https://docs.djangoproject.com/en/2.0/intro/tutorial02
在setting.py中,在中间件MiddleWare添加这么一句:
'django.middleware.locale.LocaleMiddleware','
这样你的管理后台就是中文化的了。
默认的 Django后台,均显示Django adminsteration略微难看,下面是解决的方法。
编辑项目目录下的urls.py,在末尾添加这三行:
admin.site.site_header = u'我是网站后台'
admin.site.index_title = u'我是站点管理'
admin.site.site_url = 'www.xxx.xxx'
在appname/apps.py可以设置有关app的消息,请看下面的文章: here
修改相应的models.py即可,在定义的Meta中定义:
class Meta:
verbose_name = u'单数名称'
verbose_name_plural = u'复数名称'
我们已经知道了,如果仅仅是进行三步的数据迁移,是不够的,还必须向网站进行注册. 在自己项目的目录下,找到admin.py:
from learn_logs.models import Topic, Entry
admin.site.register(Topic)
admin.site.register(Entry)
当然,这个项目是你自己的项目,但是这个模式不变的,在你在models.py中写了一个字段,数据迁移完成后必须在admin.py中注册一下。
这一步是不用数据迁移的,可以直接使用的
和你注册时的状况一样,看看下面的代码:
python manage.py shell
>>> from learn_log2.models import Topic
>>> topic.objects.all()
...
>>> for topic in topics:
print(topic.id, topic)
...
>>> t = Topic.objects.get(id=1)
>>> t.text
>>> t.date_added
这里的视图文件就是你要向浏览者展示的页面,是你以后主要编写代码的地方。 先写一个最简单的。
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello,this is my first view")
为了能够访问这个页面,需要指定urls.
在应用目录下新建一个urls.py文件,写入下面的代码:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index')
]
不知道大家能不能看出一些含义在里面,path方法需要的参数需要你在views.py中事先定义好,这一点是显而易见的。
项目的urls.py,
from django.conf.urls import include, path
# 版本1.0的是url,上面是2.0
from django.contrib import admin
urlpatterns = [
path('app', include('app.urls'))
]
这里path方法中的include也是同样的思路,上面的app就是你自己的项目名称。
这时你在浏览器中127.0.0.1:8000/polls中就可以查看页面了,当然,后台使用
python manage.py runserver
这是我的python基础教程,入门级别的
如果在源代码中插入中文的话,可能会报编码错误,需要在头文件中加入:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
print “你好,世界”;
name = raw_input();
print 'hello',name
name = raw_input('please enter your name');
print 'hello', name
# 输入非数字的话,就会报错
birth = int(raw_input('birth:'))
# 展示程序
root@yubo-2:~/test/python# cat test.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import math
str = raw_input("请输入");
print "你输入的内容是:" , str
root@yubo-2:~/test/python# python test.py
请输入hechun
你输入的内容是: hechun
root@yubo-2:~/test/python#
# input 输入,支持python表达式
str = input("请输入");
print "你输入的内容是:", str
root@yubo-2:~/test/python# python test.py
请输入[x*5 for x in range(2,10,2)]
你输入的内容是: [10, 20, 30, 40]
上面的输入输出是文件执行的,如果需要解释器来运行,则需要导入相关的模块。
>>> import sys
>>> sys.stdout.write('Python rules!\n')
Python rules!
>>> value = sys.stdin.readline()
hello, yubo
>>> value
'hello, yubo\n'
>>> print(value)
hello, yubo
print '\\\n\\\'
## 打印
# \
# \
## 防止转义
print r'\\\n\\\'
## 多行内容使用三引号 ‘'''...'''
print ''' hello
world
yubo
'''
## 打印布尔值
print 3>2
## unicode编码转换成utf-8
print u'ABC'.encode('utf-8')
print u'中文'.encode('utf-8')
## 格式化输出 这里???
# 格式转换
print 'Hello, %s' % 'wrold'
直接创建:
list('python')
output is here:
['p', 'y', 't', 'h', 'o', 'n']
这是字典。下面是实例
>>> my_objects = {}
>>> my_objects['id1'] = []
>>> my_objects
{'id1': []}
>>> my_objects['id2'] = []
>>> my_objects
{'id1': [], 'id2': []}
>>> my_objects['id3'] = []
>>> my_objects
{'id1': [], 'id2': [], 'id3': []}
>>> my_objects['id2'].append('some data, but could be anything')
>>> my_objects
{'id1': [], 'id2': ['some data, but could be anything'], 'id3': []}
>>> my_objects['id2'][0]
'some data, but could be anything'
>>> my_objects2 = {}
>>> my_objects2['id1'] = {}
>>> my_objects2['id2'] = {}
>>> my_objects2['id3'] = {}
>>> my_objects2
{'id2': {}, 'id3': {}, 'id1': {}}
>>> my_objects2['id2']['new_key'] = 'some data'
>>> my_objects
{'id2': ['some data be added'], 'id3': [], 'id1': []}
>>> my_objects2
{'id2': {'new_key': 'some data'}, 'id3': {}, 'id1': {}}
>>> my_objects2['id2']['new_key']
'some data'
对c的理解还是太肤浅,现在简单记录下来。
博士数学论坛是国内最全面的中文数学专业网站(http://www.math.org.cn)。 博士家园旗下网站,建站于2004年。主要是推广普及数学信息和知识,使数学走近寻常百姓。享受稳定快速的数学资源服务(数学课堂,数学博客),交流数学问题,寻找数学朋友等。 欢迎真正讨论问题的学生,老师,科研人员参与。每一位用到数学的人都应该有个论坛帐号。现在免费赠送邀请码,快去注册一个会员账号吧!
呵呵
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。 贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关
摘自百度百科
[0-1背包问题]
马踏棋盘
最小生成树的prim和kruskal的算法
设有n个正整数,将它们连接成一排,组成一个最大的多位整数。 例如:n=3时,3个整数13,312,343,连成的最大整数为34331213。 又如:n=4时,4个整数7,13,4,246,连成的最大整数为7424613。 输入:n N个数 输出:连成的多位数 算法分析:此题很容易想到使用贪心法,在考试时有很多同学把整数按从大到小的顺序连接起来,测试题目的例子也都符合,但最后测试的结果却不全对。按这种标准,我们很容易找到反例:12,121应该组成12121而非12112,那么是不是相互包含的时候就从小到大呢?也不一定,如12,123就是12312而非12123,这种情况就有很多种了。是不是此题不能用贪心法呢? 其实此题可以用贪心法来求解,只是刚才的标准不对,正确的标准是:先把整数转换成字符串,然后在比较a+b和b+a,如果a+b>=b+a,就把a排在b的前面,反之则把a排在b的后面。
思想: 对这k个子问题分别求解。如果子问题的规模仍然不够小,则再划分为k个子问题,如此递归的进行下去,直到问题规模足够小,很容易求出其解为止。
设计一个递归算法生成n个元素{r1,r2,…,rn}的全排列。
设R={r1,r2,…,rn}是要进行排列的n个元素,
Ri=R-{ri}
举一个具体的例子
递归的理解是这样:
比如,计算一个数组的前n个元素:
int sum(int arr[], int n);
int result = sum(arr, n);
这里的参数不要写具体的值,比如10.
“最小情况” 是基本事实,也就是取一个特定的值对于n来说。
这里就是递归中比较难的一部分了, 很多人确定不了基本事实。上面的例子中,有以下三个选择:
sum(arr, 2);
sum(arr, 1);
sum(arr, 0);
这里,就得选第三个,因为加上第0个元素可以为加上一个0.
sum(arr, n);
这样就计算了第n个元素,我们在一个比较小的情况下需要执行最小问题的”n-1”.
所以,对于sum(arr, n) 就是用 sum(arr, n -1) 加上arr[ n - 1]
递归需要把基本事实和递归例子整合在一起。下面是递归的一般模板:
if ( base case )
// return some simple expression
else // recursive case
{
// some work before
// recursive call
// some work after
}
更复杂的情况是:
if ( base case 1 )
// return some simple expression
else if ( base case 2 )
// return some simple expression
else if ( base case 3 )
// return some simple expression
else if ( recursive case 1 )
{
// some work before
// recursive call
// some work after
}
else if ( recursive case 2 )
{
// some work before
// recursive call
// some work after
}
else // recursive case 3
{
// some work before
// recursive call
// some work after
}
例子的代码在下面: