マルチスレッド プログラミングと並列コンピューティングの例: 先物取引およびタクシー配車ソフトウェアのアルゴリズム

マルチスレッド プログラミングと並列コンピューティングの例: 先物取引およびタクシー配車ソフトウェアのアルゴリズム

ここに画像の説明を挿入

マルチプロセッサおよびマルチコア システムの普及により、並列コンピューティングは現実の問題を解決する際の重要なパフォーマンス向上手段となっています。このブログでは、先物取引と配車マッチング アルゴリズムという 2 つの魅力的で実践的なシナリオについて詳しく説明することで、並列コンピューティングが実際の問題においてどのように大きな利点をもたらすかを示します。

先物取引とマルチスレッド プログラミング

先物取引の概念: 先物取引は、取引所を介して二者間で将来の受け渡される資産または現金決済契約を売買する金融取引です。先物契約は、将来の特定の時点で、一定の量と質の資産が合意された価格で引き渡されることを規定する標準化された契約です。取引の対象となるのは、さまざまな商品(農産物、鉱物、石油など)や金融商品(通貨、債券、指数など)です。先物契約は、取引の両当事者に価格変動のリスクを軽減する機会を提供し、また投資家が潜在的な投機利益を得ることができるようにします。

先物取引と株式取引の比較

  1. 取引対象は異なります。先物取引にはさまざまな商品や金融商品が含まれますが、株式取引には企業の株式の売買が含まれます。
  2. レバレッジ効果: 先物取引には通常レバレッジ効果があり、取引に参加するために証拠金の一部を支払うだけで済みます。株式取引では、通常、取引金額の全額の支払い(または信用取引を利用)が必要です。
  3. 契約の有効期限: 先物契約には固定の有効期限があり、その前に履行または清算操作が実行されます。株式取引には有効期限が定められておらず、無期限に保有することができます。
  4. 取引の方向性: 先物取引では、投資家が価格下落を予測して契約を空売りすることで利益を得ることができます。株式取引は主に長期戦略であり、価格が上昇すると利益が得られます。
  5. 取引手数料: 先物取引手数料は、契約が標準化されており、取引が比較的簡単であるため、通常は低くなります。株式取引コストは、取引手数料や印紙税などを含めて高額になる場合があります。
  6. リスク管理: 先物取引では、証拠金および期末決済システムを通じてリスクをより適切に管理できます。株式取引のリスク管理は、投資家自身のリスク管理能力にかかっています。

つまり、先物取引と株式取引には、取引対象、レバレッジ、契約期限、取引方向、手数料、リスク管理の点で大きな違いがあります。投資家は、自身の経験、リスク許容度、投資目標に基づいて、適切な取引市場を選択します。

先物取引のプロセスと収益方法: 先物取引にはトウモロコシ農家 (売り手) とトウモロコシ加工工場の所有者 (買い手) がいるとします。トウモロコシ農家は6 6を期待しています6か月10,000 10,00010 トウモロコシ000ポンド。価格変動リスクを確保するため、両者は先物取引を行うこととした。

  1. 先物契約の決定:
    2 つの当事者が取引所を使用して、固定価格 (たとえば、1 ポンドあたり 2 ドル) で 6 か月以内に 10,000 ポンドのトウモロコシを引き渡すことを規定する先物契約を作成します。農家は契約でショート(売り)ポジションをとり、加工業者は契約でロング(買い)ポジションをとります。

  2. 先物取引プロセス:
    先物取引では、取引に参加するために必要な最低金額である証拠金の支払いが必要です。証拠金率が 10% であると仮定すると、双方がそれぞれ10,000 10,000を支払う必要があります。10 000ポンド× 2 \times 2× 2ドル× 10 % = 2,000 \times 10\% = 2,000× 10%=2 000ドル。また、時価決済は毎日行われ、オープン約定の損益は市場価格に応じて決済されます。

  3. 収益方法と考えられる損益状況:
    a) 6 か月後、トウモロコシの市場価格が2.5 ポンドあたり 2.5に上昇すると仮定します。2.50ドル。加工工場のオーナーが10,000 10,00010 000ポンドのトウモロコシの価格は2 2スポット市場では同じ量のトウモロコシの価格が2ドルですが、1 ポンドあたり2.5 2.5 です。2.50ドル。したがって、加工工場の所有者は0.5 0.5$ 0.5 /ポンド、5,000 5,0005 収益は000 。この場合、農家は高価格の恩恵を受けることはできませんが、それでも収入を確保し、価格変動のリスクを回避することができます。

b) 仮定6 66か月後、トウモロコシの市場価格は1.5 1.51.50ドル。農家は先物市場で 1 ポンド2 2スポット市場では同じ量のトウモロコシが2ドルですが、1 ポンドあたりわずか1.5 1.5 ドル1.50ドル。したがって、農家は0.5 0.5$ 0.5 /ポンド損失、増加5,000 5,0005 収益は000 。加工工場の所有者は低価格の恩恵を受けることができませんでしたが、安定したスポット価格を確保しました。

起こり得る事故
a) 取引中、先物価格が大きく変動した場合、証拠金が不足する可能性があります。取引所は必要証拠金を増やしたり、マージンコールを発行したりする場合があります。
b) 当取引所は、市場の需要または政策の調整に応じて、先物契約の仕様を変更する場合があります。
c) 契約者が満了前にポジションを決済しない場合、取引所の規定に従って受渡手続きが実行される場合があります。実際に商品の受け渡しをしたくない投資家にとっては、有効期限が切れる前にポジションを決済することが重要です。
d) 市場規制とコンプライアンスの欠如は、市場操作、インサイダー取引などの問題を引き起こす可能性があります。

上記の例を通して、先物取引は投資家が価格リスクを回避するのに役立ち、投機家は価格変動を予測することで利益を得ることができることがわかります。ただし、取引においては予期せぬ事態が発生する可能性がありますので、参加者は取引ルールや市場リスクを十分に理解する必要があります。

価格が上がっても下がっても先物はなぜ儲かるのか

金先物を例に考えてみましょう。投資家 A が金の価格が上昇すると予測すると仮定し、金先物契約を 1 つ購入することを選択します。先物契約を購入する場合、必要なのは最初の証拠金、たとえば 1,000 ドルのみです。

  1. 価格上昇:
    金の価格が 1 オンスあたり 1,500 ドルから 1,600 ドルに上昇し、1 オンスあたり 100 ドル増加したとします。Aさんのロングポジションで利益が出ました。投資家 A は、ポジションを決済して契約を売却すると、(手数料などのコストを考慮せずに) 100 米ドルの利益を得ることができます。

  2. 価格の下落:
    この時点で、投資家 B は金の価格が下落すると予測し、金先物契約を 1 つ空売りすることにしました。先物ショートとは、ロングとは対照的に、価格が下落することに賭ける手段として契約を売ることです。

金の価格が 1 オンスあたり 1500 ドルから 1400 ドルに下落し、1 オンスあたり 100 ドル下落したとします。Bさんのショートポジションで利益が出ました。投資家 B は、ポジションを閉じて契約を買い戻すことで、収入を確定し、100 米ドルの利益を得ることができます (手数料などのコストに関係なく)。

この例は、先物市場では、先物価格が上昇しているか下落しているかに関係なく、投資家が先物契約をロング(安く買ってから高く売る)またはショート(高値で売ってから安く買う)することで利益を実現できることを示しています。株式市場では、投資家が収入を得る通常の方法は、株を買って株価が上昇するのを待つ(つまりロングする)ことです。株式市場の一部の地域では空売り戦略から利益を得ることができますが、多くの市場ではこれは限られています。対照的に、先物市場では、取引戦略と収益方法に大きな柔軟性が与えられます。

マルチスレッドプログラミングの概念と背景

マルチスレッド プログラミングの概念の紹介: マルチスレッド プログラミングは、プログラムの実行を同時に実行できる複数のスレッドに分割するという基本的な考え方を持つプログラミング パラダイムです。シングルコア プロセッサ システムでは、複数のスレッドが論理的に同時に実行されますが、マルチコア プロセッサ システムでは、複数のスレッドが物理的に同時に実行できます。マルチスレッド プログラミングにより、特に最新のマルチコア プロセッサを使用する場合、プログラムはコンピューター リソースをより効率的に使用できるようになり、プログラムの応答性とパフォーマンスが向上します。

マルチスレッド プログラミングは、次のようなさまざまなシナリオで使用されます。

  1. プログラムのパフォーマンスの向上: データ処理、科学計算、サーバー処理リクエストなどの観点から、マルチスレッドはタスクを並列処理してプログラムのスループットを向上させることができます。
  2. 応答性の向上: ユーザー インターフェイス (UI) プログラムでは、1 つのスレッドを表示とユーザーの対話に使用し、別のスレッドでコンピューティング タスクを実行してインターフェイスのフリーズを回避できます。
  3. リソース共有: マルチスレッドにより、複数のタスクがデータベース接続、ファイル操作などの同じリソースを共有できます。
  4. 現実世界をシミュレートする: 物理コンピューティングやゲームなどの分野では、マルチスレッドによって現実世界の複数の同時イベントをシミュレートできます。

C++ でマルチスレッド プログラミングを使用する方法: C++11 以降、C++ 標準ライブラリは<thread><mutex><condition_variable><atomic>などのマルチスレッド サポートを提供します。以下は、C++ でマルチスレッド プログラミングを使用する方法の段階的な概要です。

  1. 必要なヘッダー ファイル (例: ) をインクルードし<thread>ます<mutex>
  2. スレッド関数を定義するか、スレッドによって実行されるタスクを含むラムダ式を使用します。
  3. スレッド オブジェクトを作成し、スレッド関数とその他の必要なパラメータ (存在する場合) を渡します。
  4. 共有リソースを保護するには、ミューテックス ( std::mutex)、アトミック操作 ( std::atomic) などを使用して、データの一貫性と正確性を確保します。
  5. 条件変数 ( std::condition_variable) を使用して、通知とスレッド間の待機を処理します。
  6. タスクが完了したら、join()スレッド オブジェクトのメソッドを呼び出して、スレッドの実行が終了するのを待ちます。
  7. 複雑な場合には、セマフォやバリアなどのより高いレベルの同期を使用できます。

C++ でマルチスレッド プログラムを作成する場合は、潜在的な問題を回避するために、デッドロック、競合状態、リソース競合などの同時プログラミングにおける一般的な問題を理解する必要があることに注意してください。

取引プロセスをシミュレートするプログラム

この C++ プログラムは、先物取引におけるさまざまな商品の価格の時系列変化と 10 人のトレーダーの取引行動をシミュレートするために使用され、マルチスレッドを使用してトレーダーの行動をシミュレートします。次のコードでは、 C++11<thread>と を使用して<mutex>基本的なマルチスレッド プログラムを構築します。このコードを正しく実行するには、C++11 以降のコンパイラが必要であることに注意してください。この例のマルチスレッドはシミュレーションのみを目的としており、完全な同時実行制御は可能ではありません。実際のプロジェクトでは、データの一貫性と正確性を確保するために、同時実行性と同期について詳しく調べる必要がある場合があります。このプログラムのトレーダーは、商品価格をランダムに変更し、商品を売買します。

#include <iostream>
#include <vector>
#include <random>
#include <ctime>
#include <fstream>
#include <thread>
#include <mutex>

using namespace std;
// g++ future_market.cpp -o exe "-std=c++11"

std::mutex mtx; // 线程之间共享的互斥

// 商品类别
class Commodity {
    
    
public:
    std::string name;
    double price;

    Commodity(const std::string& name, double initial_price)
        : name(name), price(initial_price) {
    
    }
};

// 交易者类别
class Trader {
    
    
public:
    std::string name;

    // 买入和卖出方法
    void buy(const Commodity& commodity, double price, double QUANT) const
    {
    
    
        std::lock_guard<std::mutex> lock(mtx);
        std::cout << name << " \033[32m买入\033[0m " << QUANT << " 手 " << commodity.name << " \033[1m以价格 " << price << std::endl;
    }

    void sell(const Commodity& commodity, double price, double QUANT) const
    {
    
    
        std::lock_guard<std::mutex> lock(mtx);
        std::cout << name << " \033[32m卖出\033[0m " << QUANT << " 手 " << commodity.name << " \033[1m以价格 " << price << std::endl;
    }

    Trader(const std::string& name) : name(name) {
    
    }
};

void store_price_history(const std::vector<Commodity>& commodities, int time) {
    
    
    std::ofstream history("price_history.txt", std::ios::app);
    history << "Time: " << time << std::endl;
    for (const auto& commodity : commodities) {
    
    
        history << commodity.name << " price: " << commodity.price << std::endl;
    }
    history.close();
}

void trader_action(const Trader& trader, std::vector<Commodity>& commodities) {
    
    
    std::default_random_engine RAND_ENG(std::time(0));
    std::uniform_int_distribution<int> COMMODITY_DIST(0, commodities.size() - 1);
    std::uniform_real_distribution<double> PRICE_VAR(-1.0, 1.0);
    std::uniform_real_distribution<double> QUANT_DIST(1.0, 10.0);
    std::bernoulli_distribution action_distr(0.5);

    
    for (int TIME = 0; TIME < 100; ++TIME) {
    
    
        int RAND_INDEX = COMMODITY_DIST(RAND_ENG);
        double QUANT = QUANT_DIST(RAND_ENG);
        commodities[RAND_INDEX].price += PRICE_VAR(RAND_ENG);
        store_price_history(commodities, TIME);
        
        std::cout<<" ------ 时间:第 "<<TIME/25+1<<" 周 星期 "<<(TIME/5)%5+1<<" 第 "<<TIME%5+1<<" 个交易时 ------ "<<std::endl;
        if (QUANT_DIST(RAND_ENG)>7.0 || QUANT_DIST(RAND_ENG)<3.0) {
    
    cout<<" 无 交 易 "<<endl;continue;}
        if (action_distr(RAND_ENG)) {
    
    
            trader.buy(commodities[RAND_INDEX], commodities[RAND_INDEX].price, QUANT);
        } else {
    
    
            trader.sell(commodities[RAND_INDEX], commodities[RAND_INDEX].price, QUANT);
        }
    }
}


int main() {
    
    
    cout<<" ================ 期 货 模 拟 交 易 程 序 ================= "<<endl;
    std::vector<Trader> traders = {
    
    {
    
    "李想"},{
    
    "王潮"},{
    
    "刘畅"},{
    
    "陈鱼"},{
    
    "吴恙"},{
    
    "徐愿"},{
    
    "胡岚"},{
    
    "朱梦"},{
    
    "林溪"},{
    
    "何华"}};
    std::vector<Commodity> commodities = {
    
    {
    
    "大豆", 900.0},{
    
    "玉米", 500.0},{
    
    "金属镍", 1200.0},{
    
    "金属铜", 6300.0},{
    
    "金属银", 9995.0},{
    
    "棕榈油", 1800.0}};

    std::vector<std::thread> threads;
    for (const auto& trader : traders) {
    
    
        threads.push_back(std::thread(trader_action, std::ref(trader), std::ref(commodities)));
    }

    for (auto& t : threads) {
    
    
        t.join();
    }

    return 0;
}

操作結果:
ここに画像の説明を挿入

タクシー配車ソフトウェアのマッチングアルゴリズムと並列計算

並列コンピューティングの概念と背景

並列コンピューティングの概念: 並列コンピューティングとは、マルチプロセッサまたはマルチコア システム上で複数の独立したコンピューティング タスクを同時に実行し、プログラム全体の実行速度を高速化することを指します。このアプローチにより、コンピューター システムのパフォーマンスが向上し、問題解決が高速化され、大規模で複雑な問題の解決が可能になります。

アプリケーションの背景: 並列コンピューティングは、科学技術コンピューティング、画像処理、人工知能、データマイニング、金融取引などの多くの分野で高い実用的価値があります。マルチコア プロセッサ テクノロジの開発と市場の普及に伴い、並列コンピューティングを通じてパフォーマンスと効率の向上を実現できるビジネス ニーズがますます増えています。

C++ で並列コンピューティングを使用する: C++ 自体は直接的な並列コンピューティングのサポートを提供しませんが、並列コンピューティングは次の方法で実行できます。

  1. OpenMP: OpenMP (Open Multi-Processing) は、C、C++、および Fortran 言語に基づく並列プログラミング フレームワークであり、共有メモリ マルチコア プロセッサの並列コンピューティングをサポートします。OpenMP を使用すると、コンパイラが提供するディレクティブとランタイム ライブラリを利用して、既存のコードに並列コンピューティング機能を追加できます。たとえば、C++ では、次のように並列 for ループを作成できます。
#pragma omp parallel for
for (int i = 0; i < n; i++) {
    
    
    // 并行执行的代码
}
  1. C++11 スレッド ライブラリ: C++11 では、プログラマがスレッド、ミューテックス、条件変数などのコンポーネントを使用して並列処理を実装できるようにする新しいスレッド ライブラリが導入されています。このライブラリは、POSIX スレッドや Windows スレッドなどのプリミティブ スレッド ライブラリの高レベルの抽象化を提供し、C++ プログラムでの並列コンピューティングの実装を容易にします。例えば:
#include <thread>

void my_function() {
    
    
    // 你希望并行执行的代码
}

int main() {
    
    
    std::thread t1(my_function);
    std::thread t2(my_function);
    t1.join();
    t2.join();
    return 0;
}
  1. std::sortC++17 の並列アルゴリズム ライブラリ: C++17 標準には、などの並列実行をサポートするアルゴリズム ライブラリが追加されました。実行戦略を使用すると、一般的なアルゴリズムを並列バージョンに調整することが簡単になります。例えば:
#include <algorithm>
#include <vector>
#include <execution>

int main() {
    
    
    std::vector<int> data = {
    
     /* 一些数据 */ };
    std::sort(std::execution::par, data.begin(), data.end());
    return 0;
}
  1. サードパーティ ライブラリ: Intel Thread Building Blocks (TBB)、Boost.Asio、CUDA など、C++ 専用の並列コンピューティング ライブラリもいくつかあります。これらのライブラリは、さまざまな要件に応じて、並列計算をより効率的に行うためのさまざまな並列計算メソッドを提供します。
タクシーのマッチングプロセスをシミュレーションするプログラム

んんm人の乗客がタクシーを呼びます。近くに合計nタクシーn車、タクシー、乗客は整数の座標属性を持ち、乗客に近いタクシーを優先します。

#include <iostream>
#include <vector>
#include <cmath>
#include <mutex>
#include <limits>

class Coordinate {
    
    
public:
    int x, y;

    Coordinate(int x, int y) : x(x), y(y) {
    
    }
};

double distance(const Coordinate& a, const Coordinate& b) {
    
    
    return std::sqrt(std::pow(a.x - b.x, 2) + std::pow(a.y - b.y, 2));
}

void assign_taxi(int i, const std::vector<Coordinate>& passengers,
                 const std::vector<int>& taxi_status, const std::vector<Coordinate>& taxis,
                 std::vector<int>& assigned_taxi) {
    
    
    int closest_taxi = -1;
    double min_distance = std::numeric_limits<double>::max();
    for (int j = 0; j < int(taxis.size()); ++j) {
    
    
        if (taxi_status[j] == 0) {
    
    
            double curr_distance = distance(passengers[i], taxis[j]);
            if (curr_distance < min_distance) {
    
    
                min_distance = curr_distance;
                closest_taxi = j;
            }
        }
    }
    if (closest_taxi != -1) {
    
    
        assigned_taxi[i] = closest_taxi;
    }
}

int main() {
    
    
    // 初始化乘客和出租车状态;
    std::vector<Coordinate> passengers = {
    
    {
    
    0,0},{
    
    1,9},{
    
    2,7},{
    
    8,1}};
    std::vector<Coordinate> taxis = {
    
    {
    
    1,1},{
    
    5,5},{
    
    7,7}};

    int m = int(passengers.size());
    int n = int(taxis.size());

    std::vector<int> assigned_taxi(m, -1);
    std::vector<int> taxi_status(n, 0); // 0 表示空闲,1 表示已被匹配
    std::mutex mtx;

    // 并行匹配过程;
    #pragma omp parallel for
    for (int i = 0; i < m; ++i) {
    
    
        assign_taxi(i, passengers, taxi_status, taxis, assigned_taxi);

        if (assigned_taxi[i] != -1) {
    
    
            mtx.lock();
            if (taxi_status[assigned_taxi[i]] == 0) {
    
    
                taxi_status[assigned_taxi[i]] = 1;
            } else {
    
    
                assigned_taxi[i] = -1;
            }
            mtx.unlock();
        }
    }

    // 输出匹配结果;
    for (int i = 0; i < m; ++i) {
    
    
        if (assigned_taxi[i] != -1) {
    
    
            std::cout << "\033[32m乘客\033[0m " << i << " 已匹配至 \033[32m出租车\033[0m " << assigned_taxi[i] << std::endl;
        } else {
    
    
            std::cout << "未找到匹配的出租车给乘客 " << i << std::endl;
        }
    }

    return 0;
}

コード内の次の行に注目してください。

  1. 変数std::vector<int> taxi_status(n, 0)。0 はタクシーが空いていることを意味し、1 はタクシーが一致したことを意味します。

  2. タクシー割り当てロジックは、assign_taxi繰り返しの呼び出しを容易にするために関数に個別にカプセル化されています。

  3. ミューテックスはstd::mutex mtx保護のために使用されますtaxi_status車両を割り当てようとすると、最初に以前のステータスがチェックされます。タクシーが空いている場合は、ステータスを「一致」に設定し、一致リストを更新します。

このコードは貪欲なアルゴリズムを使用しているため、大域的な最適解ではない可能性があることに注意してください。大域的な最適解を考慮する場合は、他のアルゴリズムを導入する必要があります。

操作結果:
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/hanss2/article/details/131362371