当我们面对多任务处理时,该做什么?

当我们面对多任务处理时,该做什么?,第1张

在日常工作中,多任务并行处理是我们的常态。往往一个活还没干完,另外的活又来了。用同事的话说,活总是扎堆来的。那面对这样的情况,我们应该怎么办?结合自己的工作体会,我梳理了这么几条tips:

一、避免任务来回反复切换。 不知道小伙伴们发现没有,当我们从任务A切换到任务B时,即使没有被外力干扰,也需要一定的适应过程。如果再回到任务A,就需要进行认知重构,重新回忆A的相关背景和信息,比如写信息,就要倒回去看之前写了什么内容。这样一来,任务A的绩效就会明显降低,用认知心理学的话说,这叫“转换损耗”。切换的频次越高,绩效越低。所以,当自己在干一件事情的时候,不要自己主动去做切换,要一直挖井,直到挖到水,除了中途的休息。

二、要搞清楚任务的类型。 不同工作任务的类型实际上是有区分的,有些是支撑性任务,有些是需要核心思考的任务,有些是沟通协调类任务,等等。支撑性任务,比如收发文、文件调整格式、打印等;需要核心思考的任务,认知复杂度相对较高,需要大块完整的时间来用心谋划,比如材料框架的搭建。

三、寻求别人的帮助。 面对多任务时,分清楚哪些工作是可以独立完成的,自己处在这项工作的什么环节,哪些工作是需要别人协助或参与的,别人的工作是会影响进度的必要环节还是帮助补充的。当需要同事领导帮助时,请大胆提出,一切以目标为导向,以干好工作为导向。

四、坚持“二八”法则,不苛求尽善尽美。 当面临多任务时,要克制自己的完美主义,不能将所有任务都同等对待。虽然,高标准严要求的出发点肯定是好的,但受客观条件影响,不可能什么事情都做到尽善尽美。所以,我们要适当降低预期,将80%的精力花在少数关键、确实重要的任务上,对无关紧要的降低关注度。

五、批量处理简单任务、相似任务、关联任务。 简单任务可以集中一起处理,比如回复邮件等;相似任务和关联任务也可以一并处理,因为工作背景相近,有比较强的牵引性和相关性。既然是批量处理,就涉及到另一个问题,如何防止工作遗漏。这个时候,我通常会用钉钉的稍后处理功能,、文件、文字都适用。

六、营造舒心的办公环境。 这条其实还是蛮重要的,在舒心舒服的环境中工作会有事半功倍的效果,头脑也会更加清楚,而且对很多人来说,一天中大部分的时间都花在办公桌上面,所以有必要对办公环境做一定布置,增添一点让自己放松的玩意儿、绿植等。

在某些系统中,需要你自己来构建自己的异步多任务处理框架。通过这种多任务处理,可以自己实现事件驱动编程模型的一个小部分。当然,event driven is good for computer but not for human beings,人要是事件驱动,要么他是消防队员,要么他很失败,呵呵。另外,当存在典型的情况 “等待数据->处理数据->等待数据”循环时,用异步处理能够大大增加系统的性能,尤其是出现数据和处理互相依赖的关系时。如:任务A的输出数据是任务B的输入,而B的输出又是C的输入,而且B和C在进行数据处理之前需要花费大量时间来做初始化,线性处理显然会有性能瓶颈。采用异步处理能改善这种情况,当有多个处理器时性能将得到极大的提高。

本文描述的异步多任务是通过同一进程内的调度器来调度该进程内多个异步任务,这些异步任务的真正执行是通过工作线程来完成。其模型为:各异步的任务发送请求后阻塞;当其请求的任务完成后,调度器唤醒该任务并执行相应的处理(也许会再次发送一个请求)。这时一个典型的生产者/消费者的问题:在调度器中,生产者是任务,而调度器是消费者。一旦任务的请求完成,调度器则执行该任务。
处理流程
由于scheduler是在一个进程中,因此需要先将scheduler安装到进程中,然后将各异步任务添加到scheduler,之后,各异步任务发送第一个请求等待完成。最后启动scheduler,处理各个已经完成请求。如下图所示:
任务
每个任务都应当继承自同一个基类以使得调度器可以以相同的方式处理他们。每个派生的任务都应当包含(至少)一个异步 *** 作(或所属对象),该 *** 作可以执行1~n次。每次异步 *** 作完成之后,其Run()函数将被调用以进行后续处理。因此,任务至少应当具有一个状态成员用于指示该任务所处的状态。当任务处理完毕之后,任务可以把自己从调度队列中移出。由于添加任务到调度队列的 *** 作应当由调度器而不是任务本身来做,因此,不需要Add() *** 作。因此,任务类应当象这样:
其中:
StartWorker()、Dequeue()都是由TaskBase来实现的:
int TaskBase::Dequeue()
{
Scheduler sched = SchedulerInstance::GetInstance();
int ret = ErrNone;
m_Mutex->Lock();
if (sched && m_Status != TaskPending)
sched->Remove(this);
else
ret = ErrTaskBusy;
m_Mutex->Unlock();
return ret;
}

int TaskBase::StartWorker()
{
Scheduler sched = SchedulerInstance::GetInstance();
int ret = ErrNone;
m_Mutex->Lock();
if (sched && (m_Status != TaskPending || m_Status != NotAvailable))
{
m_Worker->RunThread(this);
}
else
ret = ErrTaskBusy;
m_Mutex->Unlock();
return ret;
}

void TaskBase::CancelWorker()
{
Scheduler sched = SchedulerInstance::GetInstance();
m_Mutex->Lock();
if (sched && m_Status == TaskPending)
{
m_Worker->Cancel();
m_Status = TaskCancelled;
}
m_Mutex->Unlock();
}
由于使用了工作线程来进行真正的异步 *** 作,因此,应当有一个静态函数来作为线程的入口函数。
其实现为:
void WorkerThread::ThreadFunction(void aData)
{
TaskBase task = static_cast<TaskBase>(aData);
if (task)
task->IssueRequest();
// Notify the Scheduler
Scheduler sched = SchedulerInstance::GetInstance();
if (sched)
sched->Notify();
}
由于工作线程的实现与平台相关,因此此处列出Linux平台的典型实现:
void LinuxThread::RunThread(void aData)
{
pthread_create(&m_TID, NULL, WorkerThread::ThreadFunction, aData);
Scheduler sched = SchedulerInstance::GetInstance();
if (sched)
sched->Notify();
}

void LinuxThread::Cancel()
{
pthread_cancel(m_TID);
Scheduler sched = SchedulerInstance::GetInstance();
if (sched)
sched->Notify();
}

windows任务处理可分为两类:协同式多任务和抢先式多任务处理模式。

1)使用协同式多任务处理模式,CPU的分配直接由应用程序决定,所以系统性能好坏取决于应用程序设计好坏。而运行抢先式多任务处理模式,各进程占用CPU的时间由系统调度程序决定,当调度程序检测出有比当前任务优先级更高的程序事件后,暂停当前任务并将CPU时间分配给优先级更高的进程。所有的Win16应用程序都在同一台虚拟机上运行,各程序之间采用的是协同式多任务处理。每个Win32应用程序和MS-DOS应用程序都具有自己专用的虚拟机,其进程按抢先式多任务处理方式运行。

2)

Windows中的多任务调度策略

Windows中调度的任务有两种状态:运行状态和等待状态。正在运行的任务处于运行状 态,当该任务把CPU控制权交给其他任务后,就被置为等待状态。为了便于任务调度和保存每个任务运行的参数,Windows在装载应用程序时,由LoadModule()函数创建一任务数据库(简称TDB),该任务数据库在内存中是以链表的形式存在,TDB链表中的结点记下了每个任务切换时的堆栈指针、中断处理程序地址及此任务对应的模块句柄和实例句柄等

Windows就是根据TDB链表中存放的各个任务的数据信息来完成任务调度的。 对Windows而言,CPU属于临界资源,在某一时刻只有一个任务独占CPU。为了合理分配CPU,提高系统的性能,Windows根据任务是否存在等待事件来进行任务调度。如果当前任务没有事件可供处理,那么就应该把控制权交给其他具有等待事件的任务。为了记录每个任务的等待事件个数,在TDB链表中,为每个任务建立一个事件计数器(TDB偏移6处的值),系统调度程序就是根据该计数器来进行任务调度。我们可以通过Windows中未公开的核心函数PostEvent()把指定任务的事件计数器值增1,人为地伪造一个事件,引起相应的任务被唤醒。 当有多个任务都具有等待事件时,Windows采用的最高优先级(HPF)算法进行调度。为此Windows定义了任务的优先权值:范围从-32到+15,任务的优先权值越小,它的优先级就越高,其任务结点在TDB链表中的位置也越靠前。而在实际应用中,绝大多数Windows应用程序的优先值都是0,若优先权值相同,则按先来先服务的原则进行。任务的优先权值只对具有等待事件的任务生效,如果一个任务没有等待事件,即使优先权再高,也不会被调度。 若当前任务所分配的时间片用完或当前任务再无等待事件,任务调度程序就要释放当前任务的控制权,把控制权交给已选中的可调度任务。但在WindowsAPI中并没直接公开这样一个函数,许多具有释放控制权功能的函数都被隐藏在GetMessage()或PeekMessage()这样的消息函数中,当应用程序在消息环中没有消息可供接收时,它就会把控制权交给别的任务,以防止当前任务进入死循环。当前任务释放控制权以后,如果没一个任务被调度程序选中,调度程序就会使Windows进入系统空闲状态,相应的电源管理软件就会使整个系统处于低能耗的睡眠状态,直至有任务被唤醒而重新开始正常运转

知识点延伸--多任务处理

多任务处理是指用户可以在同一时间内运行多个应用程序,每个应用程序被称作一个任务Linux、windows就是支持多任务的 *** 作系统,比起单任务系统它的功能增强了许多。当多任务 *** 作系统使用某种任务调度策略允许两个或更多进程并发共享一个处理器时,事实上处理器在某一时刻只会给一件任务提供服务。因为任务调度机制保证不同任务之间的切换速度十分迅速,因此给人多个任务同时运行的错觉。多任务系统中有3个功能单位:任务、进程和线程。

分时
就是说每个任务分若干时间
在这个时间里多任务中的一个任务使用CPU
当该任务的时间片用完了
就换下一个任务
有一本叫
计算机 *** 作系统
的书
上面有讲


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/13220279.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-06-22
下一篇 2023-06-22

发表评论

登录后才能评论

评论列表(0条)

保存