はじめに
P#とは、Microsoftが開発中のプログラミング言語です。
非同期&イベント駆動型という特徴を持ち、非同期処理のテストを容易にすることに重点を置いているようです。
Machine(オートマトン)、State(状態)、Event(状態遷移トリガ)を記述することによりプログラムを構築するのですが、注目すべきはこの言語、文法がC#の拡張であり、.NET Framework上で動作するのです。
つまり、「C#コードはP#コードである」という論理が成り立ちます。
夢がひろがりんぐですね。
環境構築
公式Githubはこちら。
執筆時点でのP#のバージョンは1.2.4です。
2017/9/2追記 バージョン1.3.2で検証済みです。
公式Githubには色々と文書があるので、環境構築は簡単かなーと思いきや、文書は古い内容なのか、それ通りにやってハマったのでメモします。
PSharpの入手
公式から任意のフォルダにクローンします。
> git clone https://github.com/p-org/PSharp.git
これでPSharpフォルダ以下にソリューションが生成されます。
ビルド
公式にはdotnet restore
を使えとか、build.ps1でビルドしろとか書かれていますが、うまく行きませんでした。
しかし、Visual Studio Community 2017 でPSharp.slnを開き、単純にビルドすれば通ります。
これで、PSharp/bin/net46/
以下にDLLやコンパイラなどが生成されます。
P#プロジェクトの準備
P#をコンパイルするにはプロジェクトが必要です。
C#コンソールアプリのプロジェクトを作りましょう。
このとき、ターゲットフレームワークは「.NET Framework 4.6」を指定してください。
プロジェクトを作成したら、参照設定が必要です。
PSharp/bin/net46
以下のこのDLLを参照してください。
Microsoft.PSharp.dll
そして、以下の2ファイルを用意します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.PSharp;
namespace PSharpSample
{
class Program
{
static void Main(string[] args)
{
PSharpRuntime.Create().CreateMachine(typeof(Server));
Console.ReadLine();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PSharpSample
{
event Ping; // Client sends this event to the Server
event Pong; // Server sends this event to the Client
event Unit; // Event used for local transitions
// Event used for configuration, can take a payload
event Config (target: machine);
machine Server
{
machine client;
start state Init
{
entry
{
// Instantiates the Client
this.client = create(Client);
// Sends event to client to configure it
send(this.client, Config, this);
raise(Unit); // Sends an event to itself
}
on Unit goto Active; // Performs a state transition
}
state Active
{
on Ping do async
{
// Sends a Pong event to the Client
Console.WriteLine("Receive Ping");
await Task.Delay(1000);
Console.WriteLine("Send Pong");
send(this.client, Pong);
}
}
}
machine Client
{
machine server;
start state Init
{
on Config do Configure; // Handles the event
on Unit goto Active; // Performs a state transition
}
void Configure()
{
// Receives reference to Server
this.server = (trigger as Config).target;
raise(Unit); // Sends an event to itself
}
state Active
{
entry
{
Console.WriteLine("Send Ping");
send(this.server, Ping);
}
on Pong do SendPing;
}
async Task SendPing()
{
// Sends a Ping event to the Server
Console.WriteLine("Receive Pong");
await Task.Delay(1000);
Console.WriteLine("Send Ping");
send(this.server, Ping);
}
}
}
以上の2ファイルが用意できたら、Machines.psharpのプロパティをいじりましょう。
Machines.psharp -> プロパティ -> ビルドアクション -> コンパイル
に設定します。
これをしないと次のコンパイルが通りません。
以上ができたら、Visual Studioのウィンドウを一旦閉じます。
コンパイル
Developer Command Prompt for VS 2017を開いてください。
そうしたら、PSharp/bin/net46
へ移動しましょう。
そして、以下のコマンドを実行します。
> PSharpCompiler.exe /s:${SOLUTION_PATH}
上記の${SOLUTION_PATH}
には、先程準備したプロジェクトのソリューションを指定してください。
これでコンパイルが通るはずです。
EXEができているので、実行してみてください。
Send Ping
Receive Ping
Send Pong
Receive Pong
Send Ping
Receive Ping
...
Visual Studio上でビルド
2017/9/2追記 本節の内容を変更しました。
Visual Studio上でビルドを行なうには、まずテキストエディタを使ってプロジェクトの.csproj
ファイルを開きます。
以下のようなXMLファイルですね。
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
...
これにImport
タグを2つ追加します。
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
↓これを追加
<Import Project="$(PSharpBinaries)\PSharp.targets" />
↓これも追加
<Import Project="$(PSharpBinaries)\PSharp.vs2017.targets" />
<PropertyGroup>
...
上記の$(PSharpBinaries)
には、PSharp\bin\net46
の絶対パスを記述します。
これができたら、再度プロジェクトを開いてください。
もう一度ビルドアクションの設定をします。
今度は、
Machines.psharp -> プロパティ -> ビルドアクション -> PSharp
が選択できるようになっているので、これに設定します。
あとはVisual Studioによるビルドが通るようになっているので、開発が容易になります。
おわりに
公式サイトには、IntelliSenseなどの記述もあるのですが、私の環境ではどうもうまくいきませんでした。
ここで紹介させていただいた内容はすぐに変更される恐れがありますので、ご注意願います。
ともあれ、これでP#の開発が可能になりました。
Git内にはサンプルも含まれていますので、是非試してみてください。