【置顶】异步原理和实现
和异步相似的概念最初是在读书的时候 计算机原理中讲解CPU时间最优分配算法时接触的。
问题:
1.假设代码片段壹 执行时间需要20MS ,假设代码片段贰需要执行时间30MS ,代码片段叁需要执行时间5MS
2.代码执行流程是 壹贰叁,其中他们3个片段执行顺序可打乱。
3.代码执行完毕需要的时间为,壹:20MS 贰:50MS ,叁:55MS。平均等待时间为41MS。任务全部完成需要时间55MS
4.这种对于执行需要高CPU的时候会带来更多的平均等待时间(响应时间,延迟), 有没有办法能够减少呢?
方案分析:
1.假设壹可以拆分为A1 A1 2个子任务块执行时间分别为10MS。假设贰可以拆分为B1,B2,B3, 2个子任务块执行时间分别为10MS。叁为子任务C1
2.按照原顺序壹贰叁,拆分新顺序为 A1 A2 B1 B2 B3 C1,如果执行顺序为 A1 B1 C1 A2 B2 B3 ,那么代码壹贰叁执行完毕时间为(25+35+55)平均等待时间为38MS。任务全部完成需要时间55MS,这样看来 平均等待时间就更少了,
3.这里的守恒定律是通过增加内耗从而换来平均等待时间减少,划分粒度需要根据梳理情况进行调整,一般大方向是特别耗时或者等待的东西才进行异步处理 比如IO操作,异步代码的背后可以是结合多线程甚至是系统级手法来进行非阻塞运行。
4.这里提供的异步是基于回调形式提供给使用者的,因此理论上任何可通过回调来执行的东西都可以利用该原理进行异步操作 实现原理: 1.这里有一个基本原则就是代码壹贰叁 他们之间没有关联,拆分出来的子任务的相对顺序不能改变。 2.用队列去做这个子任务的容器,子任务可以通过 闭包去实现。 3.这里的原理是异步的核心思想,大量的异步手法都能在该思想的应用
异步的应用:TODO
示例代码:
1.示例1展示了基本运作原理,但是C++代码稍显晦涩,
2.示例2通过 语法糖让写法尚未好看一些
3.如果语言级别能够植入该种手法,那么书写起来将会很美观,如go
示例代码1
class AsyncQueue
{
public:
inline void Post(const std::function<void(AsyncQueue*)> & cb)
{
_queue.push(cb);
}
void Run()
{
while (true)
{
InternalYield();
while (_queue.empty() == false)
{
auto cb = _queue.front();
_queue.pop();
cb(this);
}
}
}
private:
inline void InternalYield()
{
std::this_thread::sleep_for(std::chrono::nanoseconds(1));
}
private:
std::queue<std::function<void(AsyncQueue*)>> _queue;
};
AsyncQueue async;
void func1()
{
async.Post([=](AsyncQueue*async)
{
cout << "11111111" << endl;
});
async.Post([=](AsyncQueue*async)
{
cout << "22222222" << endl;
async->Post([=](AsyncQueue*async)
{
cout << "3333333333" << endl;
});
});
}
void func2()
{
async.Post([=](AsyncQueue*async)
{
cout << "AAAAAAA" << endl;
async->Post([=](AsyncQueue*async)
{
cout << "BBBBBBBBBBB" << endl;
func1();
async->Post([=](AsyncQueue*async)
{
cout << "CCCCCCCC" << endl;
});
});
});
}
int main(int argc, char* argv[])
{
func2();
async.Run();
::system("pause");
return 0;
}
示例代码2
class AsyncQueue
{
public:
inline void Post(const std::function<void(AsyncQueue*)> & cb)
{
_queue.push(cb);
}
void Run()
{
while (true)
{
InternalYield();
while (_queue.empty() == false)
{
auto cb = _queue.front();
_queue.pop();
cb(this);
}
}
}
private:
inline void InternalYield()
{
std::this_thread::sleep_for(std::chrono::nanoseconds(1));
}
private:
std::queue<std::function<void(AsyncQueue*)>> _queue;
};
class Async
{
public:
static Async*Create()
{
return new Async;
}
public:
Async* Add(const std::function<void(Async*)>&cb)
{
_queue.push(cb);//pass by copy
return this;
}
void Continue()
{
if (_queue.empty() == false)
{
auto cb = _queue.front();
_queue.pop();
cb(this);
if (_queue.empty())
{
delete this;
}
}
else
{
delete this;
}
}
void Go()
{
this->Continue();
}
private:
std::queue<std::function<void(Async *)>> _queue;
};
AsyncQueue async;
void func1()
{
Async::Create()->Add([=](Async*as)
{
//step 1
cout << "11111111" << endl;
as->Continue();
})->Add([=](Async*as)
{
//step 2
cout << "2222222222222" << endl;
async.Post([=](AsyncQueue*async)
{
cout << "3333333333" << endl;
});
})->Go();
}
void func2()
{
//step 1
Async::Create()->Add([=](Async*as)
{
//step 1
cout << "AAAAAAA" << endl;
as->Continue();
})->Add([=](Async*as)
{
//step 2
cout << "BBBBBBBBBBB" << endl;
async.Post([=](AsyncQueue*async)
{
func1();
as->Continue();
});
})->Add([=](Async*as)
{
//strp3
async.Post([=](AsyncQueue*async)
{
cout << "CCCCCCCC" << endl;
});
})->Go();
}
int main(int argc, char* argv[])
{
func2();
async.Run();
_CrtDumpMemoryLeaks();
::system("pause");
return 0;
}